]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/win32/winmain.cpp
Move winapi.h/c from findlib to lib for inclusion in multiple places
[bacula/bacula] / bacula / src / filed / win32 / 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 #ifndef HAVE_WIN32
24 #define HAVE_CYGWIN 1
25 #endif
26
27 #include <unistd.h>
28 #include <lmcons.h>
29 #include <ctype.h>
30 #include "winbacula.h"
31 #include "wintray.h"
32 #include "winservice.h"
33 #include <signal.h>
34 #include <pthread.h>
35 #include "../../lib/winapi.h"
36
37 extern int BaculaMain(int argc, char *argv[]);
38 extern void terminate_filed(int sig);
39 extern DWORD g_error;
40 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
41 extern void d_msg(const char *, int, int, const char *, ...);
42
43 /* Globals */
44 HINSTANCE       hAppInstance;
45 const char      *szAppName = "Bacula";
46 DWORD           mainthreadId;
47
48 /* Imported variables */
49 extern DWORD    g_servicethread;
50
51 #define MAX_COMMAND_ARGS 100
52 static char *command_args[MAX_COMMAND_ARGS] = {"bacula-fd", NULL};
53 static int num_command_args = 1;
54 static pid_t main_pid;
55 static pthread_t main_tid;
56
57 /*
58  * WinMain parses the command line and either calls the main App
59  * routine or, under NT, the main service routine.
60  */
61 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
62                    PSTR CmdLine, int iCmdShow)
63 {
64    char *szCmdLine = CmdLine;
65    char *wordPtr, *tempPtr;
66    int i, quote;
67
68    /* Save the application instance and main thread id */
69    hAppInstance = hInstance;
70    mainthreadId = GetCurrentThreadId();
71
72    main_pid = getpid();
73    main_tid = pthread_self();
74
75    /*
76     * Funny things happen with the command line if the
77     * execution comes from c:/Program Files/bacula/bacula.exe
78     * We get a command line like: Files/bacula/bacula.exe" options
79     * I.e. someone stops scanning command line on a space, not
80     * realizing that the filename is quoted!!!!!!!!!!
81     * So if first character is not a double quote and
82     * the last character before first space is a double
83     * quote, we throw away the junk.
84     */
85
86    wordPtr = szCmdLine;
87    while (*wordPtr && *wordPtr != ' ')
88       wordPtr++;
89    if (wordPtr > szCmdLine)      /* backup to char before space */
90       wordPtr--;
91    /* if first character is not a quote and last is, junk it */
92    if (*szCmdLine != '"' && *wordPtr == '"') {
93       szCmdLine = wordPtr + 1;
94    }
95 // MessageBox(NULL, szCmdLine, "Cmdline", MB_OK);
96
97    /* Build Unix style argc *argv[] */      
98
99    /* Don't NULL command_args[0] !!! */
100    for (i=1;i<MAX_COMMAND_ARGS;i++)
101       command_args[i] = NULL;
102
103    wordPtr = szCmdLine;
104    quote = 0;
105    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
106       wordPtr++;
107    if (*wordPtr == '\"') {
108       quote = 1;
109       wordPtr++;
110    } else if (*wordPtr == '/') {
111       /* Skip Windows options */
112       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
113          wordPtr++;
114       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
115          wordPtr++;
116    }
117    if (*wordPtr) {
118       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
119          tempPtr = wordPtr;
120          if (quote) {
121             while (*tempPtr && *tempPtr != '\"')
122             tempPtr++;
123             quote = 0;
124          } else {
125             while (*tempPtr && *tempPtr != ' ')
126             tempPtr++;
127          }
128          if (*tempPtr)
129             *(tempPtr++) = '\0';
130          command_args[num_command_args++] = wordPtr;
131          wordPtr = tempPtr;
132          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
133             wordPtr++;
134          if (*wordPtr == '\"') {
135             quote = 1;
136             wordPtr++;
137          }
138       }
139    }
140
141    /*
142     * Now process Windows command line options
143     *   as defined by ATT
144     *
145     * Make the command-line lowercase and parse it
146     */
147    for (i = 0; i < (int)strlen(szCmdLine); i++) {
148       szCmdLine[i] = tolower(szCmdLine[i]);
149    }
150
151    bool argfound = false;
152    for (i = 0; i < (int)strlen(szCmdLine); i++) {
153       if (szCmdLine[i] <= ' ') {
154          continue;
155       }
156
157       if (szCmdLine[i] == '-') {
158          while (szCmdLine[i] && szCmdLine[i] != ' ') {
159             i++;
160          }
161          continue;
162       }
163
164       argfound = true;
165
166       /* Now check for command-line arguments */
167
168       /* /service start service */
169       if (strncmp(&szCmdLine[i], BaculaRunService, strlen(BaculaRunService)) == 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 (strncmp(&szCmdLine[i], BaculaRunAsUserApp, strlen(BaculaRunAsUserApp)) == 0) {
175          /* Bacula is being run as a user-level program */
176          return BaculaAppMain();
177       }
178       /* /install */
179       if (strncmp(&szCmdLine[i], BaculaInstallService, strlen(BaculaInstallService)) == 0) {
180          /* Install Bacula as a service */
181          bacService::InstallService();
182          i += strlen(BaculaInstallService);
183          continue;
184       }
185       /* /remove */
186       if (strncmp(&szCmdLine[i], BaculaRemoveService, strlen(BaculaRemoveService)) == 0) {
187          /* Remove the Bacula service */
188          bacService::RemoveService();
189          i += strlen(BaculaRemoveService);
190          continue;
191       }
192
193       /* /about */
194       if (strncmp(&szCmdLine[i], BaculaShowAbout, strlen(BaculaShowAbout)) == 0) {
195          /* Show Bacula's about box */
196          bacService::ShowAboutBox();
197          i += strlen(BaculaShowAbout);
198          continue;
199       }
200
201       /* /status */
202       if (strncmp(&szCmdLine[i], BaculaShowStatus, strlen(BaculaShowStatus)) == 0) {
203          /* Show Bacula's status box */                             
204          bacService::ShowStatus();
205          i += strlen(BaculaShowStatus);
206          continue;
207       }
208
209       /* /kill */
210       if (strncmp(&szCmdLine[i], BaculaKillRunningCopy, strlen(BaculaKillRunningCopy)) == 0) {
211          /* Kill running copy of Bacula */
212          bacService::KillRunningCopy();
213          i += strlen(BaculaKillRunningCopy);
214          continue;
215       }
216
217       /* /help */
218       if (strncmp(&szCmdLine[i], BaculaShowHelp, strlen(BaculaShowHelp)) == 0) {
219          MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK|MB_ICONINFORMATION);
220          i += strlen(BaculaShowHelp);
221          continue;
222       }
223       
224       MessageBox(NULL, szCmdLine, "Bad Command Line Options", MB_OK);
225
226       /* Show the usage dialog */
227       MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION);
228       break;
229    }
230
231    /* If no arguments were given then just run */
232    if (!argfound) {
233       BaculaAppMain();
234    }
235    return 0;
236 }
237
238
239 /*
240  * Called as a thread from BaculaAppMain()
241  * Here we handle the Windows messages
242  */
243 //DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
244 void *Main_Msg_Loop(LPVOID lpwThreadParam) 
245 {
246    DWORD old_servicethread = g_servicethread;
247
248
249    pthread_detach(pthread_self());
250
251    /* Since we are the only thread with a message loop
252     * mark ourselves as the service thread so that
253     * we can receive all the window events.
254     */
255    g_servicethread = GetCurrentThreadId();
256
257    /* Create tray icon & menu if we're running as an app */
258    bacMenu *menu = new bacMenu();
259    if (menu == NULL) {
260 //    log_error_message("Could not create sys tray menu");
261       PostQuitMessage(0);
262    }
263
264
265    /* Now enter the Windows message handling loop until told to quit! */
266    MSG msg;
267    while (GetMessage(&msg, NULL, 0,0) ) {
268       TranslateMessage(&msg);
269       DispatchMessage(&msg);
270    }
271
272    if (menu != NULL) {
273       delete menu;
274    }
275
276    if (old_servicethread != 0) { /* started as NT service */
277       /* Mark that we're no longer running */
278       g_servicethread = 0;
279
280       /* Tell the service manager that we've stopped. */
281       ReportStatus(SERVICE_STOPPED, g_error, 0);
282    }  
283    /* Tell main program to go away */
284    terminate_filed(0);
285
286    /* Should not get here */
287    pthread_kill(main_tid, SIGTERM);   /* ask main thread to terminate */
288    sleep(1);
289    kill(main_pid, SIGTERM);           /* ask main thread to terminate */
290    _exit(0);
291 }
292  
293
294 /*
295  * This is the main routine for Bacula when running as an application
296  * (under Windows 95 or Windows NT)
297  * Under NT, Bacula can also run as a service.  The BaculaServerMain routine,
298  * defined in the bacService header, is used instead when running as a service.
299  */
300 int BaculaAppMain()
301 {
302  /* DWORD dwThreadID; */
303    pthread_t tid;
304
305    HMODULE hLib = LoadLibrary("KERNEL32.DLL");
306    if (hLib) {
307       /* create file calls */
308       p_CreateFileA = (t_CreateFileA)
309           GetProcAddress(hLib, "CreateFileA");
310       p_CreateFileW = (t_CreateFileW)
311           GetProcAddress(hLib, "CreateFileW");      
312
313       /* attribute calls */
314       p_GetFileAttributesA = (t_GetFileAttributesA)
315           GetProcAddress(hLib, "GetFileAttributesA");
316       p_GetFileAttributesW = (t_GetFileAttributesW)
317           GetProcAddress(hLib, "GetFileAttributesW");
318       p_GetFileAttributesExA = (t_GetFileAttributesExA)
319           GetProcAddress(hLib, "GetFileAttributesExA");
320       p_GetFileAttributesExW = (t_GetFileAttributesExW)
321           GetProcAddress(hLib, "GetFileAttributesExW");
322       p_SetFileAttributesA = (t_SetFileAttributesA)
323           GetProcAddress(hLib, "SetFileAttributesA");
324       p_SetFileAttributesW = (t_SetFileAttributesW)
325           GetProcAddress(hLib, "SetFileAttributesW");
326       /* process calls */
327       p_SetProcessShutdownParameters = (t_SetProcessShutdownParameters)
328           GetProcAddress(hLib, "SetProcessShutdownParameters");
329       /* backup calls */
330       p_BackupRead = (t_BackupRead)
331           GetProcAddress(hLib, "BackupRead");
332       p_BackupWrite = (t_BackupWrite)
333           GetProcAddress(hLib, "BackupWrite");
334       /* char conversion calls */
335       p_WideCharToMultiByte = (t_WideCharToMultiByte)
336           GetProcAddress(hLib, "WideCharToMultiByte");
337       p_MultiByteToWideChar = (t_MultiByteToWideChar)
338           GetProcAddress(hLib, "MultiByteToWideChar");
339
340       /* find files */
341       p_FindFirstFileA = (t_FindFirstFileA)
342           GetProcAddress(hLib, "FindFirstFileA"); 
343       p_FindFirstFileW = (t_FindFirstFileW)
344           GetProcAddress(hLib, "FindFirstFileW");       
345       p_FindNextFileA = (t_FindNextFileA)
346           GetProcAddress(hLib, "FindNextFileA");
347       p_FindNextFileW = (t_FindNextFileW)
348           GetProcAddress(hLib, "FindNextFileW");
349       /* set and get directory */
350       p_SetCurrentDirectoryA = (t_SetCurrentDirectoryA)
351           GetProcAddress(hLib, "SetCurrentDirectoryA");
352       p_SetCurrentDirectoryW = (t_SetCurrentDirectoryW)
353           GetProcAddress(hLib, "SetCurrentDirectoryW");       
354       p_GetCurrentDirectoryA = (t_GetCurrentDirectoryA)
355           GetProcAddress(hLib, "GetCurrentDirectoryA");
356       p_GetCurrentDirectoryW = (t_GetCurrentDirectoryW)
357           GetProcAddress(hLib, "GetCurrentDirectoryW");      
358       FreeLibrary(hLib);
359    }
360
361    
362    hLib = LoadLibrary("MSVCRT.DLL");
363    if (hLib) {
364       /* unlink */
365       p_wunlink = (t_wunlink)
366       GetProcAddress(hLib, "_wunlink");
367       /* wmkdir */
368       p_wmkdir = (t_wmkdir)
369       GetProcAddress(hLib, "_wmkdir");
370       /* wopen */
371       p_wopen = (t_wopen)
372       GetProcAddress(hLib, "_wopen");
373
374       FreeLibrary(hLib);
375    }
376
377    
378    hLib = LoadLibrary("ADVAPI32.DLL");
379    if (hLib) {
380       p_OpenProcessToken = (t_OpenProcessToken)
381          GetProcAddress(hLib, "OpenProcessToken");
382       p_AdjustTokenPrivileges = (t_AdjustTokenPrivileges)
383          GetProcAddress(hLib, "AdjustTokenPrivileges");
384       p_LookupPrivilegeValue = (t_LookupPrivilegeValue)
385          GetProcAddress(hLib, "LookupPrivilegeValueA");
386       FreeLibrary(hLib);
387    }
388
389    WSA_Init();
390    /*  
391     * Even if these are defined, don't use on old 
392     *  platforms.
393     */
394    if (bacService::IsWin95()) {
395       p_BackupRead = NULL;
396       p_BackupWrite = NULL;
397
398       p_CreateFileW = NULL;          
399       p_GetFileAttributesW = NULL;          
400       p_GetFileAttributesExW = NULL;
401           
402       p_SetFileAttributesW = NULL;
403                 
404       p_FindFirstFileW = NULL;
405       p_FindNextFileW = NULL;
406       p_SetCurrentDirectoryW = NULL;
407       p_GetCurrentDirectoryW = NULL;
408
409       p_wunlink = NULL;
410       p_wmkdir = NULL;
411       p_wopen = NULL;
412    }
413
414    /* Set this process to be the last application to be shut down. */
415    if (p_SetProcessShutdownParameters) {
416       p_SetProcessShutdownParameters(0x100, 0);
417    }
418
419    HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
420    if (hservwnd != NULL) {
421       /* We don't allow multiple instances! */
422       MessageBox(NULL, "Another instance of Bacula is already running", szAppName, MB_OK);
423       _exit(0);
424    }
425
426
427    /* Create a thread to handle the Windows messages */
428 // (void)CreateThread(NULL, 0, Main_Msg_Loop, NULL, 0, &dwThreadID);
429    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
430
431    /* Call the "real" Bacula */
432    BaculaMain(num_command_args, command_args);
433    PostQuitMessage(0);
434    WSACleanup();
435    _exit(0);
436 }