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