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 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
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
57 # define _WIN32_IE 0x0501
59 # define _WIN32_IE 0x0401
62 #define _WIN32_WINNT 0x0501
66 HINSTANCE appInstance;
68 bool opt_debug = false;
69 bool have_service_api;
70 DWORD service_thread_id = 0;
73 #define MAX_COMMAND_ARGS 100
74 static char *command_args[MAX_COMMAND_ARGS] = {LC_APP_NAME, NULL};
75 static int num_command_args = 1;
76 static pid_t main_pid;
77 static pthread_t main_tid;
79 const char usage[] = APP_NAME "[/debug] [/service] [/run] [/kill] [/install] [/remove] [/help]\n";
83 * Main Windows entry point.
85 * We parse the command line and either calls the main App
86 * or starts up the service.
88 int WINAPI WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, PSTR CmdLine,
91 char *cmdLine = CmdLine;
92 char *wordPtr, *tempPtr;
94 OSVERSIONINFO osversioninfo;
95 osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
98 /* Save the application instance and main thread id */
99 appInstance = Instance;
100 mainthreadId = GetCurrentThreadId();
102 if (GetVersionEx(&osversioninfo) &&
103 osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
104 have_service_api = true;
108 main_tid = pthread_self();
110 INITCOMMONCONTROLSEX initCC = {
111 sizeof(INITCOMMONCONTROLSEX),
115 InitCommonControlsEx(&initCC);
118 * Funny things happen with the command line if the
119 * execution comes from c:/Program Files/bacula/bacula.exe
120 * We get a command line like: Files/bacula/bacula.exe" options
121 * I.e. someone stops scanning command line on a space, not
122 * realizing that the filename is quoted!!!!!!!!!!
123 * So if first character is not a double quote and
124 * the last character before first space is a double
125 * quote, we throw away the junk.
129 while (*wordPtr && *wordPtr != ' ')
131 if (wordPtr > cmdLine) /* backup to char before space */
133 /* if first character is not a quote and last is, junk it */
134 if (*cmdLine != '"' && *wordPtr == '"') {
135 cmdLine = wordPtr + 1;
139 * Build Unix style argc *argv[] for the main "Unix" code
140 * stripping out any Windows options
143 /* Don't NULL command_args[0] !!! */
144 for (i=1;i<MAX_COMMAND_ARGS;i++) {
145 command_args[i] = NULL;
148 char *pszArgs = bstrdup(cmdLine);
151 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
153 if (*wordPtr == '\"') {
156 } else if (*wordPtr == '/') {
157 /* Skip Windows options */
158 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
160 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
164 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
167 while (*tempPtr && *tempPtr != '\"')
171 while (*tempPtr && *tempPtr != ' ')
176 command_args[num_command_args++] = wordPtr;
178 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
180 if (*wordPtr == '\"') {
188 * Now process Windows command line options. Most of these options
189 * are single shot -- i.e. we accept one option, do something and
192 for (i = 0; i < (int)strlen(cmdLine); i++) {
193 char *p = &cmdLine[i];
196 continue; /* toss junk */
200 break; /* syntax error */
203 /* Start as a service? */
204 if (strncasecmp(p, "/service", 8) == 0) {
205 return baculaServiceMain(); /* yes, run as a service */
208 /* Stop any running copy? */
209 if (strncasecmp(p, "/kill", 5) == 0) {
210 return stopRunningBacula();
213 /* Run app as user program? */
214 if (strncasecmp(p, "/run", 4) == 0) {
215 return BaculaAppMain(); /* yes, run as a user program */
218 /* Install Bacula in registry? */
219 if (strncasecmp(p, "/install", 8) == 0) {
220 return installService(p+8); /* Pass command options */
223 /* Remove Bacula registry entry? */
224 if (strncasecmp(p, "/remove", 7) == 0) {
225 return removeService();
228 /* Set debug mode? -- causes more dialogs to be displayed */
229 if (strncasecmp(p, "/debug", 6) == 0) {
231 i += 6; /* skip /debug */
235 /* Display help? -- displays usage */
236 if (strncasecmp(p, "/help", 5) == 0) {
237 MessageBox(NULL, usage, APP_DESC, MB_OK|MB_ICONINFORMATION);
241 MessageBox(NULL, cmdLine, _("Bad Command Line Option"), MB_OK);
243 /* Show the usage dialog */
244 MessageBox(NULL, usage, APP_DESC, MB_OK | MB_ICONINFORMATION);
248 return BaculaAppMain();
251 #ifndef HAVE_TRAY_MONITOR
252 /* Minimalist winproc when don't have tray monitor */
253 LRESULT CALLBACK bacWinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
260 return DefWindowProc(hwnd, iMsg, wParam, lParam);
266 * Called as a thread from BaculaAppMain()
267 * Here we handle the Windows messages
269 void *Main_Msg_Loop(LPVOID lpwThreadParam)
273 pthread_detach(pthread_self());
276 * Since we are the only thread with a message loop
277 * mark ourselves as the service thread so that
278 * we can receive all the window events.
280 service_thread_id = GetCurrentThreadId();
282 #ifdef HAVE_TRAY_MONITOR
283 /* Create tray icon & menu if we're running as an app */
284 trayMonitor *monitor = new trayMonitor();
285 if (monitor == NULL) {
290 /* Create a window to handle Windows messages */
293 baclass.cbSize = sizeof(baclass);
295 baclass.lpfnWndProc = bacWinProc;
296 baclass.cbClsExtra = 0;
297 baclass.cbWndExtra = 0;
298 baclass.hInstance = appInstance;
299 baclass.hIcon = NULL;
300 baclass.hCursor = NULL;
301 baclass.hbrBackground = NULL;
302 baclass.lpszMenuName = NULL;
303 baclass.lpszClassName = APP_NAME;
304 baclass.hIconSm = NULL;
306 RegisterClassEx(&baclass);
308 if (CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
309 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
310 NULL, NULL, appInstance, NULL) == NULL) {
315 /* Now enter the Windows message handling loop until told to quit! */
316 while (GetMessage(&msg, NULL, 0,0) ) {
317 TranslateMessage(&msg);
318 DispatchMessage(&msg);
321 /* If we get here, we are shutting down */
323 #ifdef HAVE_TRAY_MONITOR
324 if (monitor != NULL) {
329 if (have_service_api) {
330 /* Mark that we're no longer running */
331 service_thread_id = 0;
332 /* Tell the service manager that we've stopped. */
333 ReportStatus(SERVICE_STOPPED, service_error, 0);
335 /* Tell main "Unix" program to go away */
338 /* Should not get here */
339 pthread_kill(main_tid, SIGTERM); /* ask main thread to terminate */
341 kill(main_pid, SIGTERM); /* kill main thread */
347 * This is the main routine for Bacula when running as an application,
348 * or after the service has started up.
353 DWORD dwCharsWritten;
357 /* If no arguments were given then just run */
358 if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
363 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
365 /* Start up Volume Shadow Copy (only on FD) */
368 /* Startup networking */
371 /* Set this process to be the last application to be shut down. */
372 if (p_SetProcessShutdownParameters) {
373 p_SetProcessShutdownParameters(0x100, 0);
376 /* Create a thread to handle the Windows messages */
377 pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0);
379 /* Call the Unix Bacula daemon */
380 BaculaMain(num_command_args, command_args);
381 PostQuitMessage(0); /* terminate our main message loop */
388 void pause_msg(const char *file, const char *func, int line, const char *msg)
392 bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
394 bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
396 MessageBox(NULL, buf, "Pause", MB_OK);