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