2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2011 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.
31 * Kern Sibbald, August 2007
33 * Note, some of the original Bacula Windows startup and service handling code
34 * was derived from VNC code that was used in apcupsd then ported to
35 * Bacula. However, since then the code has been significantly enhanced
36 * and largely rewritten.
38 * Evidently due to the nature of Windows startup code and service
39 * handling code, certain similarities remain. Thanks to the original
42 * This is a generic main routine, which is used by all three
43 * of the daemons. Each one compiles it with slightly different
55 # define _WIN32_IE 0x0501
57 # define _WIN32_IE 0x0401
60 #define _WIN32_WINNT 0x0501
65 HINSTANCE appInstance;
67 bool opt_debug = false;
68 bool have_service_api;
69 DWORD service_thread_id = 0;
72 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz);
75 #define MAX_COMMAND_ARGS 100
76 static char *command_args[MAX_COMMAND_ARGS] = {LC_APP_NAME, NULL};
77 static int num_command_args = 1;
78 static pid_t main_pid;
79 static pthread_t main_tid;
81 const char usage[] = APP_NAME "[/debug] [/service] [/run] [/kill] [/install] [/remove] [/help]\n";
85 * Main Windows entry point.
87 * We parse the command line and either calls the main App
88 * or starts up the service.
90 int WINAPI WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, PSTR CmdLine,
93 char *cmdLine = CmdLine;
94 char *wordPtr, *tempPtr;
96 OSVERSIONINFO osversioninfo;
97 osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
100 /* Save the application instance and main thread id */
101 appInstance = Instance;
102 mainthreadId = GetCurrentThreadId();
104 if (GetVersionEx(&osversioninfo) &&
105 osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
106 have_service_api = true;
109 GetWindowsVersionString(win_os, sizeof(win_os));
112 main_tid = pthread_self();
114 INITCOMMONCONTROLSEX initCC = {
115 sizeof(INITCOMMONCONTROLSEX),
119 InitCommonControlsEx(&initCC);
122 * Funny things happen with the command line if the
123 * execution comes from c:/Program Files/bacula/bacula.exe
124 * We get a command line like: Files/bacula/bacula.exe" options
125 * I.e. someone stops scanning command line on a space, not
126 * realizing that the filename is quoted!!!!!!!!!!
127 * So if first character is not a double quote and
128 * the last character before first space is a double
129 * quote, we throw away the junk.
133 while (*wordPtr && *wordPtr != ' ')
135 if (wordPtr > cmdLine) /* backup to char before space */
137 /* if first character is not a quote and last is, junk it */
138 if (*cmdLine != '"' && *wordPtr == '"') {
139 cmdLine = wordPtr + 1;
143 * Build Unix style argc *argv[] for the main "Unix" code
144 * stripping out any Windows options
147 /* Don't NULL command_args[0] !!! */
148 for (i=1;i<MAX_COMMAND_ARGS;i++) {
149 command_args[i] = NULL;
152 char *pszArgs = bstrdup(cmdLine);
155 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
157 if (*wordPtr == '\"') {
160 } else if (*wordPtr == '/') {
161 /* Skip Windows options */
162 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
164 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
168 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
171 while (*tempPtr && *tempPtr != '\"')
175 while (*tempPtr && *tempPtr != ' ')
180 command_args[num_command_args++] = wordPtr;
182 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
184 if (*wordPtr == '\"') {
192 * Now process Windows command line options. Most of these options
193 * are single shot -- i.e. we accept one option, do something and
196 for (i = 0; i < (int)strlen(cmdLine); i++) {
197 char *p = &cmdLine[i];
200 continue; /* toss junk */
204 break; /* syntax error */
207 /* Start as a service? */
208 if (strncasecmp(p, "/service", 8) == 0) {
209 return baculaServiceMain(); /* yes, run as a service */
212 /* Stop any running copy? */
213 if (strncasecmp(p, "/kill", 5) == 0) {
214 return stopRunningBacula();
217 /* Run app as user program? */
218 if (strncasecmp(p, "/run", 4) == 0) {
219 return BaculaAppMain(); /* yes, run as a user program */
222 /* Install Bacula in registry? */
223 if (strncasecmp(p, "/install", 8) == 0) {
224 return installService(p+8); /* Pass command options */
227 /* Remove Bacula registry entry? */
228 if (strncasecmp(p, "/remove", 7) == 0) {
229 return removeService();
232 /* Set debug mode? -- causes more dialogs to be displayed */
233 if (strncasecmp(p, "/debug", 6) == 0) {
235 i += 6; /* skip /debug */
239 /* Display help? -- displays usage */
240 if (strncasecmp(p, "/help", 5) == 0) {
241 MessageBox(NULL, usage, APP_DESC, MB_OK|MB_ICONINFORMATION);
245 MessageBox(NULL, cmdLine, _("Bad Command Line Option"), MB_OK);
247 /* Show the usage dialog */
248 MessageBox(NULL, usage, APP_DESC, MB_OK | MB_ICONINFORMATION);
252 return BaculaAppMain();
255 #ifndef HAVE_TRAY_MONITOR
256 /* Minimalist winproc when don't have tray monitor */
257 LRESULT CALLBACK bacWinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
264 return DefWindowProc(hwnd, iMsg, wParam, lParam);
270 * Called as a thread from BaculaAppMain()
271 * Here we handle the Windows messages
273 void *Main_Msg_Loop(LPVOID lpwThreadParam)
277 pthread_detach(pthread_self());
280 * Since we are the only thread with a message loop
281 * mark ourselves as the service thread so that
282 * we can receive all the window events.
284 service_thread_id = GetCurrentThreadId();
286 #ifdef HAVE_TRAY_MONITOR
287 /* Create tray icon & menu if we're running as an app */
288 trayMonitor *monitor = new trayMonitor();
289 if (monitor == NULL) {
294 /* Create a window to handle Windows messages */
297 baclass.cbSize = sizeof(baclass);
299 baclass.lpfnWndProc = bacWinProc;
300 baclass.cbClsExtra = 0;
301 baclass.cbWndExtra = 0;
302 baclass.hInstance = appInstance;
303 baclass.hIcon = NULL;
304 baclass.hCursor = NULL;
305 baclass.hbrBackground = NULL;
306 baclass.lpszMenuName = NULL;
307 baclass.lpszClassName = APP_NAME;
308 baclass.hIconSm = NULL;
310 RegisterClassEx(&baclass);
312 if (CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
313 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
314 NULL, NULL, appInstance, NULL) == NULL) {
319 /* Now enter the Windows message handling loop until told to quit! */
320 while (GetMessage(&msg, NULL, 0,0) ) {
321 TranslateMessage(&msg);
322 DispatchMessage(&msg);
325 /* If we get here, we are shutting down */
327 #ifdef HAVE_TRAY_MONITOR
328 if (monitor != NULL) {
333 if (have_service_api) {
334 /* Mark that we're no longer running */
335 service_thread_id = 0;
336 /* Tell the service manager that we've stopped. */
337 ReportStatus(SERVICE_STOPPED, service_error, 0);
339 /* Tell main "Unix" program to go away */
342 /* Should not get here */
343 pthread_kill(main_tid, SIGTERM); /* ask main thread to terminate */
345 kill(main_pid, SIGTERM); /* kill main thread */
351 * This is the main routine for Bacula when running as an application,
352 * or after the service has started up.
357 DWORD dwCharsWritten;
361 /* If no arguments were given then just run */
362 if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
367 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
369 /* Start up Volume Shadow Copy (only on FD) */
372 /* Startup networking */
375 /* Set this process to be the last application to be shut down. */
376 if (p_SetProcessShutdownParameters) {
377 p_SetProcessShutdownParameters(0x100, 0);
380 /* Create a thread to handle the Windows messages */
381 pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0);
383 /* Call the Unix Bacula daemon */
384 BaculaMain(num_command_args, command_args);
385 PostQuitMessage(0); /* terminate our main message loop */
392 void pause_msg(const char *file, const char *func, int line, const char *msg)
396 bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
398 bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
400 MessageBox(NULL, buf, "Pause", MB_OK);
407 #ifndef PRODUCT_UNLICENSED
408 #define PRODUCT_UNLICENSED 0xABCDABCD
409 #define PRODUCT_BUSINESS 0x00000006
410 #define PRODUCT_BUSINESS_N 0x00000010
411 #define PRODUCT_CLUSTER_SERVER 0x00000012
412 #define PRODUCT_DATACENTER_SERVER 0x00000008
413 #define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C
414 #define PRODUCT_DATACENTER_SERVER_CORE_V 0x00000027
415 #define PRODUCT_DATACENTER_SERVER_V 0x00000025
416 #define PRODUCT_ENTERPRISE 0x00000004
417 #define PRODUCT_ENTERPRISE_E 0x00000046
418 #define PRODUCT_ENTERPRISE_N 0x0000001B
419 #define PRODUCT_ENTERPRISE_SERVER 0x0000000A
420 #define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E
421 #define PRODUCT_ENTERPRISE_SERVER_CORE_V 0x00000029
422 #define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F
423 #define PRODUCT_ENTERPRISE_SERVER_V 0x00000026
424 #define PRODUCT_HOME_BASIC 0x00000002
425 #define PRODUCT_HOME_BASIC_E 0x00000043
426 #define PRODUCT_HOME_BASIC_N 0x00000005
427 #define PRODUCT_HOME_PREMIUM 0x00000003
428 #define PRODUCT_HOME_PREMIUM_E 0x00000044
429 #define PRODUCT_HOME_PREMIUM_N 0x0000001A
430 #define PRODUCT_HYPERV 0x0000002A
431 #define PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT 0x0000001E
432 #define PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING 0x00000020
433 #define PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY 0x0000001F
434 #define PRODUCT_PROFESSIONAL 0x00000030
435 #define PRODUCT_PROFESSIONAL_E 0x00000045
436 #define PRODUCT_PROFESSIONAL_N 0x00000031
437 #define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018
438 #define PRODUCT_SERVER_FOR_SMALLBUSINESS_V 0x00000023
439 #define PRODUCT_SERVER_FOUNDATION 0x00000021
440 #define PRODUCT_SMALLBUSINESS_SERVER 0x00000009
441 #define PRODUCT_SOLUTION_EMBEDDEDSERVER 0x00000038
442 #define PRODUCT_STANDARD_SERVER 0x00000007
443 #define PRODUCT_STANDARD_SERVER_CORE 0x0000000D
444 #define PRODUCT_STANDARD_SERVER_CORE_V 0x00000028
445 #define PRODUCT_STANDARD_SERVER_V 0x00000024
446 #define PRODUCT_STARTER 0x0000000B
447 #define PRODUCT_STARTER_E 0x00000042
448 #define PRODUCT_STARTER_N 0x0000002F
449 #define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017
450 #define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014
451 #define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015
452 #define PRODUCT_STORAGE_WORKGROUP_SERVER 0x00000016
453 #define PRODUCT_UNDEFINED 0x00000000
454 #define PRODUCT_ULTIMATE 0x00000001
455 #define PRODUCT_ULTIMATE_E 0x00000047
456 #define PRODUCT_ULTIMATE_N 0x0000001C
457 #define PRODUCT_WEB_SERVER 0x00000011
458 #define PRODUCT_WEB_SERVER_CORE 0x0000001D
460 #define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19
461 #define SM_SERVERR2 89
462 #define VER_SERVER_NT 0x80000000
466 #ifndef PRODUCT_PROFESSIONAL
467 #define PRODUCT_PROFESSIONAL 0x00000030
469 #ifndef VER_SUITE_STORAGE_SERVER
470 #define VER_SUITE_STORAGE_SERVER 0x00002000
472 #ifndef VER_SUITE_COMPUTE_SERVER
473 #define VER_SUITE_COMPUTE_SERVER 0x00004000
477 #define VER_SUITE_WH_SERVER -1
480 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
481 typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
484 * Get Windows version display string
486 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz)
488 OSVERSIONINFOEX osvi;
492 BOOL bOsVersionInfoEx;
495 memset(&si, 0, sizeof(SYSTEM_INFO));
496 memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
498 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
500 if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
503 // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
505 pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
506 "GetNativeSystemInfo");
513 if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion > 4) {
514 bstrncpy(osbuf, TEXT("Microsoft "), maxsiz);
516 // Test for the specific product.
518 if (osvi.dwMajorVersion == 6) {
519 if (osvi.dwMinorVersion == 0) {
520 if (osvi.wProductType == VER_NT_WORKSTATION)
521 bstrncat(osbuf, TEXT("Windows Vista "), maxsiz);
523 bstrncat(osbuf, TEXT("Windows Server 2008 " ), maxsiz);
526 if (osvi.dwMinorVersion == 1) {
527 if (osvi.wProductType == VER_NT_WORKSTATION )
528 bstrncat(osbuf, TEXT("Windows 7 "), maxsiz);
530 bstrncat(osbuf, TEXT("Windows Server 2008 R2 " ), maxsiz);
533 pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
537 pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
539 dwType = PRODUCT_HOME_BASIC;
543 case PRODUCT_ULTIMATE:
544 bstrncat(osbuf, TEXT("Ultimate Edition" ), maxsiz);
546 case PRODUCT_PROFESSIONAL:
547 bstrncat(osbuf, TEXT("Professional" ), maxsiz);
549 case PRODUCT_HOME_PREMIUM:
550 bstrncat(osbuf, TEXT("Home Premium Edition" ), maxsiz);
552 case PRODUCT_HOME_BASIC:
553 bstrncat(osbuf, TEXT("Home Basic Edition" ), maxsiz);
555 case PRODUCT_ENTERPRISE:
556 bstrncat(osbuf, TEXT("Enterprise Edition" ), maxsiz);
558 case PRODUCT_BUSINESS:
559 bstrncat(osbuf, TEXT("Business Edition" ), maxsiz);
561 case PRODUCT_STARTER:
562 bstrncat(osbuf, TEXT("Starter Edition" ), maxsiz);
564 case PRODUCT_CLUSTER_SERVER:
565 bstrncat(osbuf, TEXT("Cluster Server Edition" ), maxsiz);
567 case PRODUCT_DATACENTER_SERVER:
568 bstrncat(osbuf, TEXT("Datacenter Edition" ), maxsiz);
570 case PRODUCT_DATACENTER_SERVER_CORE:
571 bstrncat(osbuf, TEXT("Datacenter Edition (core installation)" ), maxsiz);
573 case PRODUCT_ENTERPRISE_SERVER:
574 bstrncat(osbuf, TEXT("Enterprise Edition" ), maxsiz);
576 case PRODUCT_ENTERPRISE_SERVER_CORE:
577 bstrncat(osbuf, TEXT("Enterprise Edition (core installation)" ), maxsiz);
579 case PRODUCT_ENTERPRISE_SERVER_IA64:
580 bstrncat(osbuf, TEXT("Enterprise Edition for Itanium-based Systems" ), maxsiz);
582 case PRODUCT_SMALLBUSINESS_SERVER:
583 bstrncat(osbuf, TEXT("Small Business Server" ), maxsiz);
585 case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
586 bstrncat(osbuf, TEXT("Small Business Server Premium Edition" ), maxsiz);
588 case PRODUCT_STANDARD_SERVER:
589 bstrncat(osbuf, TEXT("Standard Edition" ), maxsiz);
591 case PRODUCT_STANDARD_SERVER_CORE:
592 bstrncat(osbuf, TEXT("Standard Edition (core installation)" ), maxsiz);
594 case PRODUCT_WEB_SERVER:
595 bstrncat(osbuf, TEXT("Web Server Edition" ), maxsiz);
600 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
601 if( GetSystemMetrics(SM_SERVERR2) )
602 bstrncat(osbuf, TEXT( "Windows Server 2003 R2 "), maxsiz);
603 else if (osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER)
604 bstrncat(osbuf, TEXT( "Windows Storage Server 2003"), maxsiz);
605 else if (osvi.wSuiteMask & VER_SUITE_WH_SERVER )
606 bstrncat(osbuf, TEXT( "Windows Home Server"), maxsiz);
607 else if (osvi.wProductType == VER_NT_WORKSTATION &&
608 si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
609 bstrncat(osbuf, TEXT( "Windows XP Professional x64 Edition"), maxsiz);
611 bstrncat(osbuf, TEXT("Windows Server 2003 "), maxsiz);
613 // Test for the server type.
614 if (osvi.wProductType != VER_NT_WORKSTATION) {
615 if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64) {
616 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
617 bstrncat(osbuf, TEXT( "Datacenter Edition for Itanium-based Systems" ), maxsiz);
618 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
619 bstrncat(osbuf, TEXT( "Enterprise Edition for Itanium-based Systems" ), maxsiz);
622 else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) {
623 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
624 bstrncat(osbuf, TEXT( "Datacenter x64 Edition" ), maxsiz);
625 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
626 bstrncat(osbuf, TEXT( "Enterprise x64 Edition" ), maxsiz);
627 else bstrncat(osbuf, TEXT( "Standard x64 Edition" ), maxsiz);
629 if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
630 bstrncat(osbuf, TEXT( "Compute Cluster Edition" ), maxsiz);
631 else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
632 bstrncat(osbuf, TEXT( "Datacenter Edition" ), maxsiz);
633 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
634 bstrncat(osbuf, TEXT( "Enterprise Edition" ), maxsiz);
635 else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
636 bstrncat(osbuf, TEXT( "Web Edition" ), maxsiz);
637 else bstrncat(osbuf, TEXT( "Standard Edition" ), maxsiz);
642 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
643 bstrncat(osbuf, TEXT("Windows XP "), maxsiz);
644 if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
645 bstrncat(osbuf, TEXT( "Home Edition" ), maxsiz);
647 bstrncat(osbuf, TEXT( "Professional" ), maxsiz);
650 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
651 bstrncat(osbuf, TEXT("Windows 2000 "), maxsiz);
652 if ( osvi.wProductType == VER_NT_WORKSTATION ) {
653 bstrncat(osbuf, TEXT( "Professional" ), maxsiz);
655 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
656 bstrncat(osbuf, TEXT( "Datacenter Server" ), maxsiz);
657 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
658 bstrncat(osbuf, TEXT( "Advanced Server" ), maxsiz);
659 else bstrncat(osbuf, TEXT( "Server" ), maxsiz);
663 // Include service pack (if any) and build number.
665 if (_tcslen(osvi.szCSDVersion) > 0) {
666 bstrncat(osbuf, TEXT(" ") , maxsiz);
667 bstrncat(osbuf, osvi.szCSDVersion, maxsiz);
672 snprintf(buf, 80, " (build %d)", (int)osvi.dwBuildNumber);
673 bstrncat(osbuf, buf, maxsiz);
675 if (osvi.dwMajorVersion >= 6) {
676 if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
677 bstrncat(osbuf, TEXT( ", 64-bit" ), maxsiz);
678 else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
679 bstrncat(osbuf, TEXT(", 32-bit"), maxsiz);
684 bstrncpy(osbuf, "Unknown Windows version.", maxsiz);