]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/winmain.cpp
Fix MinGW build problems.
[bacula/bacula] / bacula / src / win32 / filed / 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 extern void VSSInit();
34
35 /* Globals */
36 HINSTANCE       hAppInstance;
37 const char      *szAppName = "Bacula-fd";
38 DWORD           mainthreadId;
39 bool            silent = false;
40
41 /* Imported variables */
42 extern DWORD    g_servicethread;
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    DWORD dwCharsWritten;
61
62    /* Save the application instance and main thread id */
63    hAppInstance = hInstance;
64    mainthreadId = GetCurrentThreadId();
65
66    main_pid = getpid();
67    main_tid = pthread_self();
68
69    /*
70     * Funny things happen with the command line if the
71     * execution comes from c:/Program Files/bacula/bacula.exe
72     * We get a command line like: Files/bacula/bacula.exe" options
73     * I.e. someone stops scanning command line on a space, not
74     * realizing that the filename is quoted!!!!!!!!!!
75     * So if first character is not a double quote and
76     * the last character before first space is a double
77     * quote, we throw away the junk.
78     */
79
80    wordPtr = szCmdLine;
81    while (*wordPtr && *wordPtr != ' ')
82       wordPtr++;
83    if (wordPtr > szCmdLine)      /* backup to char before space */
84       wordPtr--;
85    /* if first character is not a quote and last is, junk it */
86    if (*szCmdLine != '"' && *wordPtr == '"') {
87       szCmdLine = wordPtr + 1;
88    }
89 // MessageBox(NULL, szCmdLine, "Cmdline", MB_OK);
90
91    /* Build Unix style argc *argv[] */      
92
93    /* Don't NULL command_args[0] !!! */
94    for (i=1;i<MAX_COMMAND_ARGS;i++)
95       command_args[i] = NULL;
96
97    char *pszArgs = bstrdup(szCmdLine);
98    wordPtr = pszArgs;
99    quote = 0;
100    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
101       wordPtr++;
102    if (*wordPtr == '\"') {
103       quote = 1;
104       wordPtr++;
105    } else if (*wordPtr == '/') {
106       /* Skip Windows options */
107       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
108          wordPtr++;
109       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
110          wordPtr++;
111    }
112    if (*wordPtr) {
113       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
114          tempPtr = wordPtr;
115          if (quote) {
116             while (*tempPtr && *tempPtr != '\"')
117                tempPtr++;
118             quote = 0;
119          } else {
120             while (*tempPtr && *tempPtr != ' ')
121             tempPtr++;
122          }
123          if (*tempPtr)
124             *(tempPtr++) = '\0';
125          command_args[num_command_args++] = wordPtr;
126          wordPtr = tempPtr;
127          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
128             wordPtr++;
129          if (*wordPtr == '\"') {
130             quote = 1;
131             wordPtr++;
132          }
133       }
134    }
135
136    /*
137     * Now process Windows command line options
138     */
139    for (i = 0; i < (int)strlen(szCmdLine); i++) {
140       if (szCmdLine[i] <= ' ') {
141          continue;
142       }
143
144       if (szCmdLine[i] != '/') {
145          break;
146       }
147
148       /* Now check for command-line arguments */
149
150       /* /silent install quietly -- no prompts */
151       if (strnicmp(&szCmdLine[i], BaculaSilent, sizeof(BaculaSilent) - 1) == 0) {
152          silent = true;
153          i += sizeof(BaculaSilent) - 1;
154          continue;
155       }
156
157       /* /service start service */
158       if (strnicmp(&szCmdLine[i], BaculaRunService, sizeof(BaculaRunService) - 1) == 0) {
159          /* Run Bacula as a service */
160          return bacService::BaculaServiceMain();
161       }
162       /* /run  (this is the default if no command line arguments) */
163       if (strnicmp(&szCmdLine[i], BaculaRunAsUserApp, sizeof(BaculaRunAsUserApp) - 1) == 0) {
164          /* Bacula is being run as a user-level program */
165          if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
166             AllocConsole();
167          }
168          WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
169
170          return BaculaAppMain();
171       }
172       /* /install */
173       if (strnicmp(&szCmdLine[i], BaculaInstallService, sizeof(BaculaInstallService) - 1) == 0) {
174          /* Install Bacula as a service */
175          return bacService::InstallService(&szCmdLine[i + sizeof(BaculaInstallService) - 1]);
176       }
177       /* /remove */
178       if (strnicmp(&szCmdLine[i], BaculaRemoveService, sizeof(BaculaRemoveService) - 1) == 0) {
179          /* Remove the Bacula service */
180          return bacService::RemoveService();
181       }
182
183       /* /about */
184       if (strnicmp(&szCmdLine[i], BaculaShowAbout, sizeof(BaculaShowAbout) - 1) == 0) {
185          /* Show Bacula's about box */
186          return bacService::ShowAboutBox();
187       }
188
189       /* /status */
190       if (strnicmp(&szCmdLine[i], BaculaShowStatus, sizeof(BaculaShowStatus) - 1) == 0) {
191          /* Show Bacula's status box */                             
192          return bacService::ShowStatus();
193       }
194
195       /* /kill */
196       if (strnicmp(&szCmdLine[i], BaculaKillRunningCopy, sizeof(BaculaKillRunningCopy) - 1) == 0) {
197          /* Kill running copy of Bacula */
198          return bacService::KillRunningCopy();
199       }
200
201       /* /help */
202       if (strnicmp(&szCmdLine[i], BaculaShowHelp, sizeof(BaculaShowHelp) - 1) == 0) {
203          MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK|MB_ICONINFORMATION);
204          return 0;
205       }
206       
207       MessageBox(NULL, szCmdLine, _("Bad Command Line Options"), MB_OK);
208
209       /* Show the usage dialog */
210       MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK | MB_ICONINFORMATION);
211
212       return 1;
213    }
214
215    /* If no arguments were given then just run */
216    if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
217       AllocConsole();
218    }
219    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
220
221    return BaculaAppMain();
222 }
223
224
225 /*
226  * Called as a thread from BaculaAppMain()
227  * Here we handle the Windows messages
228  */
229 //DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
230 void *Main_Msg_Loop(LPVOID lpwThreadParam) 
231 {
232    DWORD old_servicethread = g_servicethread;
233
234
235    pthread_detach(pthread_self());
236
237    /* Since we are the only thread with a message loop
238     * mark ourselves as the service thread so that
239     * we can receive all the window events.
240     */
241    g_servicethread = GetCurrentThreadId();
242
243    /* Create tray icon & menu if we're running as an app */
244    bacMenu *menu = new bacMenu();
245    if (menu == NULL) {
246 //    log_error_message("Could not create sys tray menu");
247       PostQuitMessage(0);
248    }
249
250    /* Now enter the Windows message handling loop until told to quit! */
251    MSG msg;
252    while (GetMessage(&msg, NULL, 0,0) ) {
253       TranslateMessage(&msg);
254       DispatchMessage(&msg);
255    }
256
257    if (menu != NULL) {
258       delete menu;
259    }
260
261    if (old_servicethread != 0) { /* started as NT service */
262       /* Mark that we're no longer running */
263       g_servicethread = 0;
264
265       /* Tell the service manager that we've stopped. */
266       ReportStatus(SERVICE_STOPPED, g_error, 0);
267    }  
268    /* Tell main program to go away */
269    terminate_filed(0);
270
271    /* Should not get here */
272    pthread_kill(main_tid, SIGTERM);   /* ask main thread to terminate */
273    sleep(1);
274    kill(main_pid, SIGTERM);           /* ask main thread to terminate */
275    _exit(0);
276 }
277  
278
279 /*
280  * This is the main routine for Bacula when running as an application
281  * (under Windows 95 or Windows NT)
282  * Under NT, Bacula can also run as a service.  The BaculaServerMain routine,
283  * defined in the bacService header, is used instead when running as a service.
284  */
285 int BaculaAppMain()
286 {
287  /* DWORD dwThreadID; */
288    pthread_t tid;
289
290    InitWinAPIWrapper();
291    VSSInit();
292
293    WSA_Init();
294
295    /* Set this process to be the last application to be shut down. */
296    if (p_SetProcessShutdownParameters) {
297       p_SetProcessShutdownParameters(0x100, 0);
298    }
299
300    HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
301    if (hservwnd != NULL) {
302       /* We don't allow multiple instances! */
303       MessageBox(NULL, _("Another instance of Bacula is already running"), szAppName, MB_OK);
304       _exit(0);
305    }
306
307    /* Create a thread to handle the Windows messages */
308    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
309
310    /* Call the "real" Bacula */
311    BaculaMain(num_command_args, command_args);
312    PostQuitMessage(0);
313    WSACleanup();
314    _exit(0);
315 }