]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/winservice.cpp
Fix path issues.
[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    opt_debug;
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
330    // Get the filename of this executable
331    if (GetModuleFileName(NULL, path, pathlength-(strlen(BaculaRunService)+2)) == 0) {
332       MessageBox(NULL, _("Unable to install Bacula File service"), szAppName, MB_ICONEXCLAMATION | MB_OK);
333       return 0;
334    }
335
336    // Append the service-start flag to the end of the path:
337    if ((int)strlen(path) + 5 + (int)strlen(BaculaRunService) + (int)strlen(pszCmdLine) < pathlength) {
338       sprintf(servicecmd, "\"%s\" %s %s", path, BaculaRunService, pszCmdLine);
339    } else {
340       log_error_message(_("Service command length too long")); 
341       MessageBox(NULL, _("Service command length too long. Service not registered."),
342           szAppName, MB_ICONEXCLAMATION | MB_OK);
343       return 0;
344    }
345
346    // How to add the Bacula service depends upon the OS
347    switch (g_platform_id) {
348
349    // Windows 95/98/Me
350    case VER_PLATFORM_WIN32_WINDOWS:
351       // Locate the RunService registry entry
352       HKEY runservices;
353       if (RegCreateKey(HKEY_LOCAL_MACHINE, 
354               "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
355               &runservices) != ERROR_SUCCESS) {
356          log_error_message(_("Cannot write System Registry")); 
357          MessageBox(NULL, _("The System Registry could not be updated - the Bacula service was not installed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
358          break;
359       }
360
361       // Attempt to add a Bacula key
362       if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) {
363          RegCloseKey(runservices);
364          log_error_message(_("Cannot add Bacula key to System Registry")); 
365          MessageBox(NULL, _("The Bacula service could not be installed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
366          break;
367       }
368
369       RegCloseKey(runservices);
370
371       // We have successfully installed the service!
372       if (opt_debug) {
373          MessageBox(NULL,
374               _("The Bacula File service was successfully installed.\n"
375               "The service may be started by double clicking on the\n"
376               "Bacula \"Start\" icon and will be automatically\n"
377               "be run the next time this machine is rebooted. "),
378               szAppName,
379               MB_ICONINFORMATION | MB_OK);
380       }
381       break;
382
383    // Windows NT, Win2K, WinXP
384    case VER_PLATFORM_WIN32_NT:
385       SC_HANDLE   hservice;
386       SC_HANDLE   hsrvmanager;
387
388       // Open the default, local Service Control Manager database
389       hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
390       if (hsrvmanager == NULL) {
391          log_error_message("OpenSCManager failed"); 
392          MessageBox(NULL,
393             _("The Service Control Manager could not be contacted - the Bacula service was not installed"),
394             szAppName, MB_ICONEXCLAMATION | MB_OK);
395          break;
396       }
397
398       // Create an entry for the Bacula service
399       hservice = CreateService(
400               hsrvmanager,                    // SCManager database
401               BAC_SERVICENAME,                // name of service
402               BAC_SERVICEDISPLAYNAME,         // name to display
403               SERVICE_ALL_ACCESS,             // desired access
404               SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
405                                                                       // service type
406               SERVICE_AUTO_START,             // start type
407               SERVICE_ERROR_NORMAL,           // error control type
408               servicecmd,                     // service's binary
409               NULL,                           // no load ordering group
410               NULL,                           // no tag identifier
411               BAC_DEPENDENCIES,               // dependencies
412               NULL,                           // LocalSystem account
413               NULL);                          // no password
414       if (hservice == NULL) {
415          CloseServiceHandle(hsrvmanager);
416          log_error_message("CreateService failed"); 
417          MessageBox(NULL,
418              _("The Bacula service could not be installed"),
419               szAppName, MB_ICONEXCLAMATION | MB_OK);
420          break;
421       }
422
423       set_service_description(hsrvmanager,hservice, 
424 _("Provides file backup and restore services. Bacula -- the network backup solution."));
425
426       CloseServiceHandle(hsrvmanager);
427       CloseServiceHandle(hservice);
428
429       // Everything went fine
430       if (opt_debug) {
431          MessageBox(NULL,
432               _("The Bacula File service was successfully installed.\n"
433               "The service may be started from the Control Panel and will\n"
434               "automatically be run the next time this machine is rebooted."),
435               szAppName,
436               MB_ICONINFORMATION | MB_OK);
437       }
438       break;
439    default:
440       log_error_message("Unknown Windows System version"); 
441       MessageBox(NULL, 
442                  _("Unknown Windows operating system.\n"     
443                  "Cannot install Bacula service.\n"),
444                  szAppName, MB_ICONEXCLAMATION | MB_OK);
445        break;     
446    };
447
448    return 0;
449 }
450
451
452 // SERVICE REMOVE ROUTINE
453 int
454 bacService::RemoveService()
455 {
456    // How to remove the Bacula service depends upon the OS
457    switch (g_platform_id) {
458
459    // Windows 95/98/Me
460    case VER_PLATFORM_WIN32_WINDOWS:
461       // Locate the RunService registry entry
462       HKEY runservices;
463       if (RegOpenKey(HKEY_LOCAL_MACHINE, 
464               "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
465               &runservices) != ERROR_SUCCESS) {
466          MessageBox(NULL, 
467             _("Could not find registry entry.\nService probably not registerd - the Bacula service was not removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
468       } else {
469          // Attempt to delete the Bacula key
470          if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS) {
471             RegCloseKey(runservices);
472             MessageBox(NULL, _("Could not delete Registry key.\nThe Bacula service could not be removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
473          }
474
475          RegCloseKey(runservices);
476          break;
477       }
478
479       // Try to kill any running copy of Bacula
480       if (!KillRunningCopy()) {
481          MessageBox(NULL,
482              _("Bacula could not be contacted, probably not running"),
483              szAppName, MB_ICONEXCLAMATION | MB_OK);
484          break;
485       }
486
487       // We have successfully removed the service!
488       if (opt_debug) {
489          MessageBox(NULL, _("The Bacula service has been removed"), szAppName, MB_ICONINFORMATION | MB_OK);
490       }
491       break;
492
493    // Windows NT, Win2K, WinXP
494    case VER_PLATFORM_WIN32_NT:
495       SC_HANDLE   hservice;
496       SC_HANDLE   hsrvmanager;
497
498       // Open the SCM
499       hsrvmanager = OpenSCManager(
500          NULL,                   // machine (NULL == local)
501          NULL,                   // database (NULL == default)
502          SC_MANAGER_ALL_ACCESS   // access required
503          );
504       if (hsrvmanager) {
505          hservice = OpenService(hsrvmanager, BAC_SERVICENAME, SERVICE_ALL_ACCESS);
506          if (hservice != NULL) {
507             SERVICE_STATUS status;
508
509             // Try to stop the Bacula service
510             if (ControlService(hservice, SERVICE_CONTROL_STOP, &status)) {
511                while(QueryServiceStatus(hservice, &status)) {
512                   if (status.dwCurrentState == SERVICE_STOP_PENDING) {
513                      Sleep(1000);
514                   } else {
515                      break;
516                   }
517                }
518
519                if (status.dwCurrentState != SERVICE_STOPPED) {
520                   MessageBox(NULL, _("The Bacula file service could not be stopped"), szAppName, MB_ICONEXCLAMATION | MB_OK);
521                }
522             }
523
524             // Now remove the service from the SCM
525             if (DeleteService(hservice)) {
526                if (opt_debug) {
527                   MessageBox(NULL, _("The Bacula file service has been removed"), szAppName, MB_ICONINFORMATION | MB_OK);
528                }
529             } else {
530                MessageBox(NULL, _("The Bacula file service could not be removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
531             }
532
533             CloseServiceHandle(hservice);
534          } else {
535             MessageBox(NULL, _("The Bacula file service could not be found"), szAppName, MB_ICONEXCLAMATION | MB_OK);
536          }
537
538          CloseServiceHandle(hsrvmanager);
539       } else {
540          MessageBox(NULL, _("The SCM could not be contacted - the Bacula file service was not removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
541       }
542       break;
543    }
544    return 0;
545 }
546
547 // USEFUL SERVICE SUPPORT ROUTINES
548
549 // Service control routine
550 void WINAPI ServiceCtrl(DWORD ctrlcode)
551 {
552     // What control code have we been sent?
553     switch(ctrlcode) {
554     case SERVICE_CONTROL_STOP:
555         // STOP : The service must stop
556         g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
557         ServiceStop();
558         break;
559
560     case SERVICE_CONTROL_INTERROGATE:
561         // QUERY : Service control manager just wants to know our state
562         break;
563
564      default:
565         // Control code not recognised
566         break;
567     }
568
569     // Tell the control manager what we're up to.
570     ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
571 }
572
573 // Service manager status reporting
574 BOOL ReportStatus(DWORD state,
575                   DWORD exitcode,
576                   DWORD waithint)
577 {
578     static DWORD checkpoint = 1;
579     BOOL result = TRUE;
580
581     // If we're in the start state then we don't want the control manager
582     // sending us control messages because they'll confuse us.
583     if (state == SERVICE_START_PENDING) {
584        g_srvstatus.dwControlsAccepted = 0;
585     } else {
586        g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
587     }
588
589     // Save the new status we've been given
590     g_srvstatus.dwCurrentState = state;
591     g_srvstatus.dwWin32ExitCode = exitcode;
592     g_srvstatus.dwWaitHint = waithint;
593
594     // Update the checkpoint variable to let the SCM know that we
595     // haven't died if requests take a long time
596     if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED)) {
597        g_srvstatus.dwCheckPoint = 0;
598     } else {
599        g_srvstatus.dwCheckPoint = checkpoint++;
600     }
601
602     // Tell the SCM our new status
603     if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus))) {
604        log_error_message(_("SetServiceStatus failed"));
605     }
606
607     return result;
608 }
609
610 // Error reporting
611 void LogErrorMsg(char *message, char *fname, int lineno)
612 {
613    char        msgbuff[256];
614    HANDLE      heventsrc;
615    char *      strings[32];
616    LPTSTR      msg;
617
618    // Get the error code
619    g_error = GetLastError();
620    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
621                  FORMAT_MESSAGE_FROM_SYSTEM,
622                  NULL,
623                  g_error,
624                  0,
625                  (LPTSTR)&msg,
626                  0,
627                  NULL);
628
629    // Use event logging to log the error
630    heventsrc = RegisterEventSource(NULL, BAC_SERVICENAME);
631
632    sprintf(msgbuff, _("\n\n%s error: %ld at %s:%d"), 
633       BAC_SERVICENAME, g_error, fname, lineno);
634    strings[0] = msgbuff;
635    strings[1] = message;
636    strings[2] = msg;
637
638    if (heventsrc != NULL) {
639       MessageBeep(MB_OK);
640
641       ReportEvent(
642               heventsrc,              // handle of event source
643               EVENTLOG_ERROR_TYPE,    // event type
644               0,                      // event category
645               0,                      // event ID
646               NULL,                   // current user's SID
647               3,                      // strings in 'strings'
648               0,                      // no bytes of raw data
649               (const char **)strings, // array of error strings
650               NULL);                  // no raw data
651
652       DeregisterEventSource(heventsrc);
653    }
654    LocalFree(msg);
655 }
656 typedef BOOL  (WINAPI * WinAPI)(SC_HANDLE, DWORD, LPVOID);
657
658 void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
659                              LPSTR lpDesc) 
660
661     SC_LOCK sclLock; 
662     LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf; 
663     SERVICE_DESCRIPTION sdBuf;
664     DWORD dwBytesNeeded;
665     WinAPI ChangeServiceDescription;
666  
667     HINSTANCE hLib = LoadLibrary("ADVAPI32.DLL");
668     if (!hLib) {
669        return;
670     }
671     ChangeServiceDescription = (WinAPI)GetProcAddress(hLib,
672        "ChangeServiceConfig2A");
673     FreeLibrary(hLib);
674     if (!ChangeServiceDescription) {
675        return;
676     }
677     
678     // Need to acquire database lock before reconfiguring. 
679     sclLock = LockServiceDatabase(hSCManager); 
680  
681     // If the database cannot be locked, report the details. 
682     if (sclLock == NULL) {
683        // Exit if the database is not locked by another process. 
684        if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
685           log_error_message("LockServiceDatabase"); 
686           return;
687        }
688  
689        // Allocate a buffer to get details about the lock. 
690        lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS)LocalAlloc( 
691             LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256); 
692        if (lpqslsBuf == NULL) {
693           log_error_message("LocalAlloc"); 
694           return;
695        }
696  
697        // Get and print the lock status information. 
698        if (!QueryServiceLockStatus( 
699               hSCManager, 
700               lpqslsBuf, 
701               sizeof(QUERY_SERVICE_LOCK_STATUS)+256, 
702               &dwBytesNeeded)) {
703           log_error_message("QueryServiceLockStatus"); 
704        }
705  
706        if (lpqslsBuf->fIsLocked) {
707           printf(_("Locked by: %s, duration: %ld seconds\n"), 
708                 lpqslsBuf->lpLockOwner, 
709                 lpqslsBuf->dwLockDuration); 
710        } else {
711           printf(_("No longer locked\n")); 
712        }
713  
714        LocalFree(lpqslsBuf); 
715        log_error_message(_("Could not lock database")); 
716        return;
717     } 
718  
719     // The database is locked, so it is safe to make changes. 
720  
721     sdBuf.lpDescription = lpDesc;
722
723     if (!ChangeServiceDescription(
724          hService,                   // handle to service
725          SERVICE_CONFIG_DESCRIPTION, // change: description
726          &sdBuf) ) {                 // value: new description
727        log_error_message("ChangeServiceConfig2");
728     }
729
730     // Release the database lock. 
731     UnlockServiceDatabase(sclLock); 
732 }