]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/libwin32/main.cpp
Suppress superfluous warning messages if SD polling
[bacula/bacula] / bacula / src / win32 / libwin32 / main.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2008 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
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.
27  */
28
29 /* 
30  * 
31  *  Kern Sibbald, August 2007
32  *
33  *  Version $Id$
34  *
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.  
39  *
40  * Evidently due to the nature of Windows startup code and service
41  *  handling code, certain similarities remain. Thanks to the original
42  *  VNC authors.
43  *
44  * This is a generic main routine, which is used by all three
45  *  of the daemons. Each one compiles it with slightly different
46  *  #defines.
47  *
48  */
49
50 #include "bacula.h"
51 #include "win32.h"
52 #include <signal.h>
53 #include <pthread.h>
54
55 #undef  _WIN32_IE
56 #ifdef MINGW64
57 # define _WIN32_IE 0x0501
58 #else
59 # define _WIN32_IE 0x0401
60 #endif  // MINGW64
61 #undef  _WIN32_WINNT
62 #define _WIN32_WINNT 0x0501
63 #include <commctrl.h>
64
65 /* Globals */
66 HINSTANCE appInstance;
67 DWORD mainthreadId;
68 bool opt_debug = false;
69 bool have_service_api;
70 DWORD service_thread_id = 0;
71
72
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;
78
79 const char usage[] = APP_NAME "[/debug] [/service] [/run] [/kill] [/install] [/remove] [/help]\n";
80
81 /*
82  *
83  * Main Windows entry point.
84  *
85  * We parse the command line and either calls the main App
86  *   or starts up the service.
87  */
88 int WINAPI WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, PSTR CmdLine, 
89                    int /*show*/)
90 {
91    char *cmdLine = CmdLine;
92    char *wordPtr, *tempPtr;
93    int i, quote;
94    OSVERSIONINFO osversioninfo;
95    osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
96
97
98    /* Save the application instance and main thread id */
99    appInstance = Instance;
100    mainthreadId = GetCurrentThreadId();
101
102    if (GetVersionEx(&osversioninfo) && 
103        osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
104       have_service_api = true;
105    }
106
107    main_pid = getpid();
108    main_tid = pthread_self();
109
110    INITCOMMONCONTROLSEX initCC = {
111       sizeof(INITCOMMONCONTROLSEX), 
112       ICC_STANDARD_CLASSES
113    };
114
115    InitCommonControlsEx(&initCC);
116
117    /*
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.
126     */
127
128    wordPtr = cmdLine;
129    while (*wordPtr && *wordPtr != ' ')
130       wordPtr++;
131    if (wordPtr > cmdLine)      /* backup to char before space */
132       wordPtr--;
133    /* if first character is not a quote and last is, junk it */
134    if (*cmdLine != '"' && *wordPtr == '"') {
135       cmdLine = wordPtr + 1;
136    }
137
138    /*
139     * Build Unix style argc *argv[] for the main "Unix" code
140     *  stripping out any Windows options 
141     */
142
143    /* Don't NULL command_args[0] !!! */
144    for (i=1;i<MAX_COMMAND_ARGS;i++) {
145       command_args[i] = NULL;
146    }
147
148    char *pszArgs = bstrdup(cmdLine);
149    wordPtr = pszArgs;
150    quote = 0;
151    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
152       wordPtr++;
153    if (*wordPtr == '\"') {
154       quote = 1;
155       wordPtr++;
156    } else if (*wordPtr == '/') {
157       /* Skip Windows options */
158       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
159          wordPtr++;
160       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
161          wordPtr++;
162    }
163    if (*wordPtr) {
164       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
165          tempPtr = wordPtr;
166          if (quote) {
167             while (*tempPtr && *tempPtr != '\"')
168                tempPtr++;
169             quote = 0;
170          } else {
171             while (*tempPtr && *tempPtr != ' ')
172             tempPtr++;
173          }
174          if (*tempPtr)
175             *(tempPtr++) = '\0';
176          command_args[num_command_args++] = wordPtr;
177          wordPtr = tempPtr;
178          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
179             wordPtr++;
180          if (*wordPtr == '\"') {
181             quote = 1;
182             wordPtr++;
183          }
184       }
185    }
186
187    /*
188     * Now process Windows command line options. Most of these options
189     *  are single shot -- i.e. we accept one option, do something and
190     *  terminate.
191     */
192    for (i = 0; i < (int)strlen(cmdLine); i++) {
193       char *p = &cmdLine[i];
194
195       if (*p <= ' ') {
196          continue;                    /* toss junk */
197       }
198
199       if (*p != '/') {
200          break;                       /* syntax error */
201       }
202
203       /* Start as a service? */
204       if (strncasecmp(p, "/service", 8) == 0) {
205          return baculaServiceMain();      /* yes, run as a service */
206       }
207
208       /* Stop any running copy? */
209       if (strncasecmp(p, "/kill", 5) == 0) {
210          return stopRunningBacula();
211       }
212
213       /* Run app as user program? */
214       if (strncasecmp(p, "/run", 4) == 0) {
215          return BaculaAppMain();         /* yes, run as a user program */
216       }
217
218       /* Install Bacula in registry? */
219       if (strncasecmp(p, "/install", 8) == 0) {
220          return installService(p+8);    /* Pass command options */
221       }
222
223       /* Remove Bacula registry entry? */
224       if (strncasecmp(p, "/remove", 7) == 0) {
225          return removeService();
226       }
227
228       /* Set debug mode? -- causes more dialogs to be displayed */
229       if (strncasecmp(p, "/debug", 6) == 0) {
230          opt_debug = true;
231          i += 6;                /* skip /debug */
232          continue;
233       }
234
235       /* Display help? -- displays usage */
236       if (strncasecmp(p, "/help", 5) == 0) {
237          MessageBox(NULL, usage, APP_DESC, MB_OK|MB_ICONINFORMATION);
238          return 0;
239       }
240       
241       MessageBox(NULL, cmdLine, _("Bad Command Line Option"), MB_OK);
242
243       /* Show the usage dialog */
244       MessageBox(NULL, usage, APP_DESC, MB_OK | MB_ICONINFORMATION);
245
246       return 1;
247    }
248    return BaculaAppMain();
249 }
250
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)
254 {
255    switch (iMsg) {
256    case WM_DESTROY:
257       PostQuitMessage(0);
258       return 0;
259    }
260    return DefWindowProc(hwnd, iMsg, wParam, lParam);
261 }
262 #endif
263
264
265 /*
266  * Called as a thread from BaculaAppMain()
267  * Here we handle the Windows messages
268  */
269 void *Main_Msg_Loop(LPVOID lpwThreadParam) 
270 {
271    MSG msg;
272
273    pthread_detach(pthread_self());
274
275    /*
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.
279     */
280    service_thread_id = GetCurrentThreadId();
281
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) {
286       PostQuitMessage(0);
287    }
288
289 #else
290    /* Create a window to handle Windows messages */
291    WNDCLASSEX baclass;
292
293    baclass.cbSize         = sizeof(baclass);
294    baclass.style          = 0;
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;
305
306    RegisterClassEx(&baclass);
307
308    if (CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
309                 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
310                 NULL, NULL, appInstance, NULL) == NULL) {
311       PostQuitMessage(0);
312    }
313 #endif
314
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);
319    }
320
321    /* If we get here, we are shutting down */
322
323 #ifdef HAVE_TRAY_MONITOR
324    if (monitor != NULL) {
325       delete monitor;
326    }
327 #endif
328
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);
334    }  
335    /* Tell main "Unix" program to go away */
336    terminate_app(0);
337
338    /* Should not get here */
339    pthread_kill(main_tid, SIGTERM);   /* ask main thread to terminate */
340    sleep(1);
341    kill(main_pid, SIGTERM);           /* kill main thread */
342    _exit(0);
343 }
344  
345
346 /*
347  * This is the main routine for Bacula when running as an application,
348  *  or after the service has started up.
349  */
350 int BaculaAppMain()
351 {
352    pthread_t tid;
353    DWORD dwCharsWritten;
354
355    OSDependentInit();
356
357    /* If no arguments were given then just run */
358    if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
359       if (opt_debug) {
360          AllocConsole();
361       }
362    }
363    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
364
365    /* Start up Volume Shadow Copy (only on FD) */
366    VSSInit();
367
368    /* Startup networking */
369    WSA_Init();
370
371    /* Set this process to be the last application to be shut down. */
372    if (p_SetProcessShutdownParameters) {
373       p_SetProcessShutdownParameters(0x100, 0);
374    }
375
376    /* Create a thread to handle the Windows messages */
377    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
378
379    /* Call the Unix Bacula daemon */
380    BaculaMain(num_command_args, command_args);
381    PostQuitMessage(0);                /* terminate our main message loop */
382
383    WSACleanup();
384    _exit(0);
385 }
386
387
388 void pause_msg(const char *file, const char *func, int line, const char *msg)
389 {
390    char buf[1000];
391    if (msg) {
392       bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
393    } else {
394       bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
395    }
396    MessageBox(NULL, buf, "Pause", MB_OK);
397 }