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