]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/winmain.cpp
kes Disable posting the WM_CLOSE message in KillRunningCopy of the
[bacula/bacula] / bacula / src / win32 / filed / winmain.cpp
1 /*
2    This file is patterned after the VNC Win32 code by ATT
3 */
4 /*
5    Bacula® - The Network Backup Solution
6
7    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
8
9    The main author of Bacula is Kern Sibbald, with contributions from
10    many others, a complete list can be found in the file AUTHORS.
11    This program is Free Software; you can redistribute it and/or
12    modify it under the terms of version two of the GNU General Public
13    License as published by the Free Software Foundation and included
14    in the file LICENSE.
15
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24    02110-1301, USA.
25
26    Bacula® is a registered trademark of John Walker.
27    The licensor of Bacula is the Free Software Foundation Europe
28    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
29    Switzerland, email:ftf@fsfeurope.org.
30 */
31
32 #include <unistd.h>
33 #include <ctype.h>
34
35 #include "bacula.h"
36 #include "winbacula.h"
37 #include "wintray.h"
38 #include "winservice.h"
39 #include <signal.h>
40 #include <pthread.h>
41
42 #undef  _WIN32_IE
43 #define _WIN32_IE 0x0401
44 #undef  _WIN32_WINNT
45 #define _WIN32_WINNT 0x0501
46 #include <commctrl.h>
47
48 extern int BaculaMain(int argc, char *argv[]);
49 extern void terminate_filed(int sig);
50 extern DWORD g_error;
51 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
52 extern void d_msg(const char *, int, int, const char *, ...);
53 extern void VSSInit();
54
55 /* Globals */
56 HINSTANCE       hAppInstance;
57 const char      *szAppName = "Bacula-fd";
58 DWORD           mainthreadId;
59 bool            opt_debug = false;
60
61 /* Imported variables */
62 extern DWORD    g_servicethread;
63
64 #define MAX_COMMAND_ARGS 100
65 static char *command_args[MAX_COMMAND_ARGS] = {"bacula-fd", NULL};
66 static int num_command_args = 1;
67 static pid_t main_pid;
68 static pthread_t main_tid;
69
70 /*
71  * WinMain parses the command line and either calls the main App
72  * routine or, under NT, the main service routine.
73  */
74 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
75                    PSTR CmdLine, int iCmdShow)
76 {
77    char *szCmdLine = CmdLine;
78    char *wordPtr, *tempPtr;
79    int i, quote;
80
81    /* Save the application instance and main thread id */
82    hAppInstance = hInstance;
83    mainthreadId = GetCurrentThreadId();
84
85    main_pid = getpid();
86    main_tid = pthread_self();
87
88    INITCOMMONCONTROLSEX    initCC = {
89       sizeof(INITCOMMONCONTROLSEX), 
90       ICC_STANDARD_CLASSES
91    };
92
93    InitCommonControlsEx(&initCC);
94
95    /*
96     * Funny things happen with the command line if the
97     * execution comes from c:/Program Files/bacula/bacula.exe
98     * We get a command line like: Files/bacula/bacula.exe" options
99     * I.e. someone stops scanning command line on a space, not
100     * realizing that the filename is quoted!!!!!!!!!!
101     * So if first character is not a double quote and
102     * the last character before first space is a double
103     * quote, we throw away the junk.
104     */
105
106    wordPtr = szCmdLine;
107    while (*wordPtr && *wordPtr != ' ')
108       wordPtr++;
109    if (wordPtr > szCmdLine)      /* backup to char before space */
110       wordPtr--;
111    /* if first character is not a quote and last is, junk it */
112    if (*szCmdLine != '"' && *wordPtr == '"') {
113       szCmdLine = wordPtr + 1;
114    }
115
116    /* Build Unix style argc *argv[] */      
117
118    /* Don't NULL command_args[0] !!! */
119    for (i=1;i<MAX_COMMAND_ARGS;i++) {
120       command_args[i] = NULL;
121    }
122
123    char *pszArgs = bstrdup(szCmdLine);
124    wordPtr = pszArgs;
125    quote = 0;
126    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
127       wordPtr++;
128    if (*wordPtr == '\"') {
129       quote = 1;
130       wordPtr++;
131    } else if (*wordPtr == '/') {
132       /* Skip Windows options */
133       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
134          wordPtr++;
135       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
136          wordPtr++;
137    }
138    if (*wordPtr) {
139       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
140          tempPtr = wordPtr;
141          if (quote) {
142             while (*tempPtr && *tempPtr != '\"')
143                tempPtr++;
144             quote = 0;
145          } else {
146             while (*tempPtr && *tempPtr != ' ')
147             tempPtr++;
148          }
149          if (*tempPtr)
150             *(tempPtr++) = '\0';
151          command_args[num_command_args++] = wordPtr;
152          wordPtr = tempPtr;
153          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
154             wordPtr++;
155          if (*wordPtr == '\"') {
156             quote = 1;
157             wordPtr++;
158          }
159       }
160    }
161
162    /*
163     * Now process Windows command line options
164     */
165    for (i = 0; i < (int)strlen(szCmdLine); i++) {
166       if (szCmdLine[i] <= ' ') {
167          continue;
168       }
169
170       if (szCmdLine[i] != '/') {
171          break;
172       }
173
174       /* Now check for command-line arguments */
175
176       /* /debug - enable debugging facilities such as console message window */
177       if (strnicmp(&szCmdLine[i], BaculaOptDebug, sizeof(BaculaOptDebug) - 1) == 0) {
178          opt_debug = true;
179          i += sizeof(BaculaOptDebug) - 1;
180          continue;
181       }
182
183       /* /service start service */
184       if (strnicmp(&szCmdLine[i], BaculaRunService, sizeof(BaculaRunService) - 1) == 0) {
185          /* Run Bacula as a service */
186          return bacService::BaculaServiceMain();
187       }
188       /* /run  (this is the default if no command line arguments) */
189       if (strnicmp(&szCmdLine[i], BaculaRunAsUserApp, sizeof(BaculaRunAsUserApp) - 1) == 0) {
190          /* Bacula is being run as a user-level program */
191          return BaculaAppMain();
192       }
193       /* /install */
194       if (strnicmp(&szCmdLine[i], BaculaInstallService, sizeof(BaculaInstallService) - 1) == 0) {
195          /* Install Bacula as a service */
196          return bacService::InstallService(&szCmdLine[i + sizeof(BaculaInstallService) - 1]);
197       }
198       /* /remove */
199       if (strnicmp(&szCmdLine[i], BaculaRemoveService, sizeof(BaculaRemoveService) - 1) == 0) {
200          /* Remove the Bacula service */
201          return bacService::RemoveService();
202       }
203
204       /* /about */
205       if (strnicmp(&szCmdLine[i], BaculaShowAbout, sizeof(BaculaShowAbout) - 1) == 0) {
206          /* Show Bacula's about box */
207          return bacService::ShowAboutBox();
208       }
209
210       /* /status */
211       if (strnicmp(&szCmdLine[i], BaculaShowStatus, sizeof(BaculaShowStatus) - 1) == 0) {
212          /* Show Bacula's status box */                             
213          return bacService::ShowStatus();
214       }
215
216       /* /kill */
217       if (strnicmp(&szCmdLine[i], BaculaKillRunningCopy, sizeof(BaculaKillRunningCopy) - 1) == 0) {
218          /* Kill running copy of Bacula */
219          return bacService::KillRunningCopy();
220       }
221
222       /* /help */
223       if (strnicmp(&szCmdLine[i], BaculaShowHelp, sizeof(BaculaShowHelp) - 1) == 0) {
224          MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK|MB_ICONINFORMATION);
225          return 0;
226       }
227       
228       MessageBox(NULL, szCmdLine, _("Bad Command Line Options"), MB_OK);
229
230       /* Show the usage dialog */
231       MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK | MB_ICONINFORMATION);
232
233       return 1;
234    }
235    return BaculaAppMain();
236 }
237
238
239 /*
240  * Called as a thread from BaculaAppMain()
241  * Here we handle the Windows messages
242  */
243 //DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
244 void *Main_Msg_Loop(LPVOID lpwThreadParam) 
245 {
246    DWORD old_servicethread = g_servicethread;
247
248    pthread_detach(pthread_self());
249
250    /* Since we are the only thread with a message loop
251     * mark ourselves as the service thread so that
252     * we can receive all the window events.
253     */
254    g_servicethread = GetCurrentThreadId();
255
256    /* Create tray icon & menu if we're running as an app */
257    bacMenu *menu = new bacMenu();
258    if (menu == NULL) {
259 //    log_error_message("Could not create sys tray menu");
260       PostQuitMessage(0);
261    }
262
263    /* Now enter the Windows message handling loop until told to quit! */
264    MSG msg;
265    while (GetMessage(&msg, NULL, 0,0) ) {
266       TranslateMessage(&msg);
267       DispatchMessage(&msg);
268    }
269
270    if (menu != NULL) {
271       delete menu;
272    }
273
274    if (old_servicethread != 0) { /* started as NT service */
275       /* Mark that we're no longer running */
276       g_servicethread = 0;
277
278       /* Tell the service manager that we've stopped. */
279       ReportStatus(SERVICE_STOPPED, g_error, 0);
280    }  
281    /* Tell main program to go away */
282    terminate_filed(0);
283
284    /* Should not get here */
285    pthread_kill(main_tid, SIGTERM);   /* ask main thread to terminate */
286    sleep(1);
287    kill(main_pid, SIGTERM);           /* ask main thread to terminate */
288    _exit(0);
289 }
290  
291
292 /*
293  * This is the main routine for Bacula when running as an application
294  * (under Windows 95 or Windows NT)
295  * Under NT, Bacula can also run as a service.  The BaculaServerMain routine,
296  * defined in the bacService header, is used instead when running as a service.
297  */
298 int BaculaAppMain()
299 {
300  /* DWORD dwThreadID; */
301    pthread_t tid;
302    DWORD dwCharsWritten;
303
304    OSDependentInit();
305
306    /* If no arguments were given then just run */
307    if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
308       if (opt_debug) {
309          AllocConsole();
310       }
311    }
312    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
313
314    VSSInit();
315
316    WSA_Init();
317
318    /* Set this process to be the last application to be shut down. */
319    if (p_SetProcessShutdownParameters) {
320       p_SetProcessShutdownParameters(0x100, 0);
321    }
322
323    HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
324    if (hservwnd != NULL) {
325       /* We don't allow multiple instances! */
326       MessageBox(NULL, _("Another instance of Bacula is already running"), szAppName, MB_OK);
327       _exit(0);
328    }
329
330    /* Create a thread to handle the Windows messages */
331    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
332
333    /* Call the "real" Bacula */
334    BaculaMain(num_command_args, command_args);
335    PostQuitMessage(0);
336    WSACleanup();
337    _exit(0);
338 }