]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/dird/winmain.cpp
Update mingw32 build instructions
[bacula/bacula] / bacula / src / win32 / dird / winmain.cpp
1 /*
2    Copyright (C) 2000-2005 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 as
6    published by the Free Software Foundation; either version 2 of
7    the License, or (at your option) any later version.
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 GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public
15    License along with this program; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17    MA 02111-1307, USA.
18
19    This file is patterned after the VNC Win32 code by ATT
20   
21 */
22
23
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <bacula.h>
27 #include <signal.h>
28 #include <pthread.h>
29
30 #include "winbacula.h"
31 //#include "wintray.h"
32 #include "winservice.h"
33
34 extern int BaculaMain(int argc, char *argv[]);
35 extern void terminate_dird(int sig);
36 extern DWORD g_error;
37 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
38 extern void d_msg(const char *, int, int, const char *, ...);
39
40 /* Globals */
41 HINSTANCE       hAppInstance;
42 const char      *szAppName = "Bacula";
43 DWORD           mainthreadId;
44
45 /* Imported variables */
46 extern DWORD    g_servicethread;
47
48 #define MAX_COMMAND_ARGS 100
49 static char *command_args[MAX_COMMAND_ARGS] = {"bacula-dird", 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
65    /* Save the application instance and main thread id */
66    hAppInstance = hInstance;
67    mainthreadId = GetCurrentThreadId();
68
69    main_pid = getpid();
70    main_tid = pthread_self();
71
72    /*
73     * Funny things happen with the command line if the
74     * execution comes from c:/Program Files/bacula/bacula.exe
75     * We get a command line like: Files/bacula/bacula.exe" options
76     * I.e. someone stops scanning command line on a space, not
77     * realizing that the filename is quoted!!!!!!!!!!
78     * So if first character is not a double quote and
79     * the last character before first space is a double
80     * quote, we throw away the junk.
81     */
82
83    wordPtr = szCmdLine;
84    while (*wordPtr && *wordPtr != ' ')
85       wordPtr++;
86    if (wordPtr > szCmdLine)      /* backup to char before space */
87       wordPtr--;
88    /* if first character is not a quote and last is, junk it */
89    if (*szCmdLine != '"' && *wordPtr == '"') {
90       szCmdLine = wordPtr + 1;
91    }
92 // MessageBox(NULL, szCmdLine, "Cmdline", MB_OK);
93
94    /* Build Unix style argc *argv[] */      
95
96    /* Don't NULL command_args[0] !!! */
97    for (i=1;i<MAX_COMMAND_ARGS;i++)
98       command_args[i] = NULL;
99
100    wordPtr = szCmdLine;
101    quote = 0;
102    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
103       wordPtr++;
104    if (*wordPtr == '\"') {
105       quote = 1;
106       wordPtr++;
107    } else if (*wordPtr == '/') {
108       /* Skip Windows options */
109       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
110          wordPtr++;
111       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
112          wordPtr++;
113    }
114    if (*wordPtr) {
115       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
116          tempPtr = wordPtr;
117          if (quote) {
118             while (*tempPtr && *tempPtr != '\"')
119             tempPtr++;
120             quote = 0;
121          } else {
122             while (*tempPtr && *tempPtr != ' ')
123             tempPtr++;
124          }
125          if (*tempPtr)
126             *(tempPtr++) = '\0';
127          command_args[num_command_args++] = wordPtr;
128          wordPtr = tempPtr;
129          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
130             wordPtr++;
131          if (*wordPtr == '\"') {
132             quote = 1;
133             wordPtr++;
134          }
135       }
136    }
137
138    /*
139     * Now process Windows command line options
140     *   as defined by ATT
141     *
142     * Make the command-line lowercase and parse it
143     */
144    for (i = 0; i < (int)strlen(szCmdLine); i++) {
145       szCmdLine[i] = tolower(szCmdLine[i]);
146    }
147
148    bool argfound = false;
149    for (i = 0; i < (int)strlen(szCmdLine); i++) {
150       if (szCmdLine[i] <= ' ') {
151          continue;
152       }
153
154       if (szCmdLine[i] == '-') {
155          while (szCmdLine[i] && szCmdLine[i] != ' ') {
156             i++;
157          }
158          continue;
159       }
160
161       argfound = true;
162
163       /* Now check for command-line arguments */
164
165       /* /service helper - probably only needed on win9x */
166       if (strncmp(&szCmdLine[i], BaculaRunServiceHelper, strlen(BaculaRunServiceHelper)) == 0
167           && g_platform_id == VER_PLATFORM_WIN32_NT) {
168          /* exit with result "okay" */
169          return 0;          
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();
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();
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 #if 0
262    /* Create tray icon & menu if we're running as an app */
263    bacMenu *menu = new bacMenu();
264    if (menu == NULL) {
265 //    log_error_message("Could not create sys tray menu");
266       PostQuitMessage(0);
267    }
268 #endif
269
270    /* Now enter the Windows message handling loop until told to quit! */
271    MSG msg;
272    while (GetMessage(&msg, NULL, 0,0) ) {
273       TranslateMessage(&msg);
274       DispatchMessage(&msg);
275    }
276
277 #if 0
278    if (menu != NULL) {
279       delete menu;
280    }
281 #endif
282
283    if (old_servicethread != 0) { /* started as NT service */
284       /* Mark that we're no longer running */
285       g_servicethread = 0;
286
287       /* Tell the service manager that we've stopped. */
288       ReportStatus(SERVICE_STOPPED, g_error, 0);
289    }  
290    /* Tell main program to go away */
291    terminate_dird(0);
292
293    /* Should not get here */
294    pthread_kill(main_tid, SIGTERM);   /* ask main thread to terminate */
295    sleep(1);
296    kill(main_pid, SIGTERM);           /* ask main thread to terminate */
297    _exit(0);
298 }
299  
300
301 /*
302  * This is the main routine for Bacula when running as an application
303  * (under Windows 95 or Windows NT)
304  * Under NT, Bacula can also run as a service.  The BaculaServerMain routine,
305  * defined in the bacService header, is used instead when running as a service.
306  */
307 int BaculaAppMain()
308 {
309  /* DWORD dwThreadID; */
310    pthread_t tid;
311
312    InitWinAPIWrapper();
313
314    WSA_Init();
315
316    /* Set this process to be the last application to be shut down. */
317    if (p_SetProcessShutdownParameters) {
318       p_SetProcessShutdownParameters(0x100, 0);
319    }
320
321 #if 0
322    HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
323    if (hservwnd != NULL) {
324       /* We don't allow multiple instances! */
325       MessageBox(NULL, _("Another instance of Bacula is already running"), szAppName, MB_OK);
326       _exit(0);
327    }
328 #endif
329
330    /* Create a thread to handle the Windows messages */
331 // (void)CreateThread(NULL, 0, Main_Msg_Loop, NULL, 0, &dwThreadID);
332    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
333
334    /* Call the "real" Bacula */
335    BaculaMain(num_command_args, command_args);
336    PostQuitMessage(0);
337    WSACleanup();
338    _exit(0);
339 }