2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2008 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 two of the GNU 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 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 John Walker.
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
35 * Note, some of the original Bacula Windows startup and service handling code
36 * was derived from VNC code that was used in apcupsd then ported to
37 * Bacula. However, since then the code has been significantly enhanced
38 * and largely rewritten.
40 * Evidently due to the nature of Windows startup code and service
41 * handling code, certain similarities remain. Thanks to the original
44 * This is a generic main routine, which is used by all three
45 * of the daemons. Each one compiles it with slightly different
56 #define _WIN32_IE 0x0401
58 #define _WIN32_WINNT 0x0501
62 HINSTANCE appInstance;
64 bool opt_debug = false;
65 bool have_service_api;
66 DWORD service_thread_id = 0;
69 #define MAX_COMMAND_ARGS 100
70 static char *command_args[MAX_COMMAND_ARGS] = {LC_APP_NAME, NULL};
71 static int num_command_args = 1;
72 static pid_t main_pid;
73 static pthread_t main_tid;
75 const char usage[] = APP_NAME "[/debug] [/service] [/run] [/kill] [/install] [/remove] [/help]\n";
79 * Main Windows entry point.
81 * We parse the command line and either calls the main App
82 * or starts up the service.
84 int WINAPI WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, PSTR CmdLine,
87 char *cmdLine = CmdLine;
88 char *wordPtr, *tempPtr;
90 OSVERSIONINFO osversioninfo;
91 osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
94 /* Save the application instance and main thread id */
95 appInstance = Instance;
96 mainthreadId = GetCurrentThreadId();
98 if (GetVersionEx(&osversioninfo) &&
99 osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
100 have_service_api = true;
104 main_tid = pthread_self();
106 INITCOMMONCONTROLSEX initCC = {
107 sizeof(INITCOMMONCONTROLSEX),
111 InitCommonControlsEx(&initCC);
114 * Funny things happen with the command line if the
115 * execution comes from c:/Program Files/bacula/bacula.exe
116 * We get a command line like: Files/bacula/bacula.exe" options
117 * I.e. someone stops scanning command line on a space, not
118 * realizing that the filename is quoted!!!!!!!!!!
119 * So if first character is not a double quote and
120 * the last character before first space is a double
121 * quote, we throw away the junk.
125 while (*wordPtr && *wordPtr != ' ')
127 if (wordPtr > cmdLine) /* backup to char before space */
129 /* if first character is not a quote and last is, junk it */
130 if (*cmdLine != '"' && *wordPtr == '"') {
131 cmdLine = wordPtr + 1;
135 * Build Unix style argc *argv[] for the main "Unix" code
136 * stripping out any Windows options
139 /* Don't NULL command_args[0] !!! */
140 for (i=1;i<MAX_COMMAND_ARGS;i++) {
141 command_args[i] = NULL;
144 char *pszArgs = bstrdup(cmdLine);
147 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
149 if (*wordPtr == '\"') {
152 } else if (*wordPtr == '/') {
153 /* Skip Windows options */
154 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
156 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
160 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
163 while (*tempPtr && *tempPtr != '\"')
167 while (*tempPtr && *tempPtr != ' ')
172 command_args[num_command_args++] = wordPtr;
174 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
176 if (*wordPtr == '\"') {
184 * Now process Windows command line options. Most of these options
185 * are single shot -- i.e. we accept one option, do something and
188 for (i = 0; i < (int)strlen(cmdLine); i++) {
189 char *p = &cmdLine[i];
192 continue; /* toss junk */
196 break; /* syntax error */
199 /* Start as a service? */
200 if (strncasecmp(p, "/service", 8) == 0) {
201 return baculaServiceMain(); /* yes, run as a service */
204 /* Stop any running copy? */
205 if (strncasecmp(p, "/kill", 5) == 0) {
206 return stopRunningBacula();
209 /* Run app as user program? */
210 if (strncasecmp(p, "/run", 4) == 0) {
211 return BaculaAppMain(); /* yes, run as a user program */
214 /* Install Bacula in registry? */
215 if (strncasecmp(p, "/install", 8) == 0) {
216 return installService(p+8); /* Pass command options */
219 /* Remove Bacula registry entry? */
220 if (strncasecmp(p, "/remove", 7) == 0) {
221 return removeService();
224 /* Set debug mode? -- causes more dialogs to be displayed */
225 if (strncasecmp(p, "/debug", 6) == 0) {
227 i += 6; /* skip /debug */
231 /* Display help? -- displays usage */
232 if (strncasecmp(p, "/help", 5) == 0) {
233 MessageBox(NULL, usage, APP_DESC, MB_OK|MB_ICONINFORMATION);
237 MessageBox(NULL, cmdLine, _("Bad Command Line Option"), MB_OK);
239 /* Show the usage dialog */
240 MessageBox(NULL, usage, APP_DESC, MB_OK | MB_ICONINFORMATION);
244 return BaculaAppMain();
247 #ifndef HAVE_TRAY_MONITOR
248 /* Minimalist winproc when don't have tray monitor */
249 LRESULT CALLBACK bacWinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
256 return DefWindowProc(hwnd, iMsg, wParam, lParam);
262 * Called as a thread from BaculaAppMain()
263 * Here we handle the Windows messages
265 void *Main_Msg_Loop(LPVOID lpwThreadParam)
269 pthread_detach(pthread_self());
272 * Since we are the only thread with a message loop
273 * mark ourselves as the service thread so that
274 * we can receive all the window events.
276 service_thread_id = GetCurrentThreadId();
278 #ifdef HAVE_TRAY_MONITOR
279 /* Create tray icon & menu if we're running as an app */
280 trayMonitor *monitor = new trayMonitor();
281 if (monitor == NULL) {
286 /* Create a window to handle Windows messages */
289 baclass.cbSize = sizeof(baclass);
291 baclass.lpfnWndProc = bacWinProc;
292 baclass.cbClsExtra = 0;
293 baclass.cbWndExtra = 0;
294 baclass.hInstance = appInstance;
295 baclass.hIcon = NULL;
296 baclass.hCursor = NULL;
297 baclass.hbrBackground = NULL;
298 baclass.lpszMenuName = NULL;
299 baclass.lpszClassName = APP_NAME;
300 baclass.hIconSm = NULL;
302 RegisterClassEx(&baclass);
304 if (CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
305 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
306 NULL, NULL, appInstance, NULL) == NULL) {
311 /* Now enter the Windows message handling loop until told to quit! */
312 while (GetMessage(&msg, NULL, 0,0) ) {
313 TranslateMessage(&msg);
314 DispatchMessage(&msg);
317 /* If we get here, we are shutting down */
319 #ifdef HAVE_TRAY_MONITOR
320 if (monitor != NULL) {
325 if (have_service_api) {
326 /* Mark that we're no longer running */
327 service_thread_id = 0;
328 /* Tell the service manager that we've stopped. */
329 ReportStatus(SERVICE_STOPPED, service_error, 0);
331 /* Tell main "Unix" program to go away */
334 /* Should not get here */
335 pthread_kill(main_tid, SIGTERM); /* ask main thread to terminate */
337 kill(main_pid, SIGTERM); /* kill main thread */
343 * This is the main routine for Bacula when running as an application,
344 * or after the service has started up.
349 DWORD dwCharsWritten;
353 /* If no arguments were given then just run */
354 if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
359 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
361 /* Start up Volume Shadow Copy (only on FD) */
364 /* Startup networking */
367 /* Set this process to be the last application to be shut down. */
368 if (p_SetProcessShutdownParameters) {
369 p_SetProcessShutdownParameters(0x100, 0);
372 /* Create a thread to handle the Windows messages */
373 pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0);
375 /* Call the Unix Bacula daemon */
376 BaculaMain(num_command_args, command_args);
377 PostQuitMessage(0); /* terminate our main message loop */
384 void pause_msg(const char *file, const char *func, int line, const char *msg)
388 bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
390 bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
392 MessageBox(NULL, buf, "Pause", MB_OK);