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