2 Copyright (C) 2000-2003 Kern Sibbald and John Walker
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.
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.
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,
19 This file is patterned after the VNC Win32 code by ATT
21 Copyright (2000) Kern E. Sibbald
29 #include "winbacula.h"
31 #include "winservice.h"
34 #include "../../findlib/winapi.h"
36 extern int BaculaMain(int argc, char **argv);
37 extern int terminate_filed(int sig);
39 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
42 HINSTANCE hAppInstance;
43 const char *szAppName = "Bacula";
46 /* Imported variables */
47 extern DWORD g_servicethread;
49 #define MAX_COMMAND_ARGS 100
50 static char *command_args[MAX_COMMAND_ARGS] = {"bacula-fd", NULL};
51 static int num_command_args = 1;
52 static pid_t main_pid;
53 static pthread_t main_tid;
56 * WinMain parses the command line and either calls the main App
57 * routine or, under NT, the main service routine.
59 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
60 PSTR CmdLine, int iCmdShow)
62 char *szCmdLine = CmdLine;
63 char *wordPtr,*tempPtr;
66 /* Save the application instance and main thread id */
67 hAppInstance = hInstance;
68 mainthreadId = GetCurrentThreadId();
71 main_tid = pthread_self();
74 * Funny things happen with the command line if the
75 * execution comes from c:/Program Files/bacula/bacula.exe
76 * We get a command line like: Files/bacula/bacula.exe" options
77 * I.e. someone stops scanning command line on a space, not
78 * realizing that the filename is quoted!!!!!!!!!!
79 * So if first character is not a double quote and
80 * the last character before first space is a double
81 * quote, we throw away the junk.
84 while (*wordPtr && *wordPtr != ' ')
86 if (wordPtr > szCmdLine) /* backup to char before space */
88 /* if first character is not a quote and last is, junk it */
89 if (*szCmdLine != '"' && *wordPtr == '"')
90 szCmdLine = wordPtr + 1;
91 // MessageBox(NULL, szCmdLine, "Cmdline", MB_OK);
93 /* Build Unix style argc *argv[] */
95 /* Don't NULL command_args[0] !!! */
96 for (i=1;i<MAX_COMMAND_ARGS;i++)
97 command_args[i] = NULL;
101 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
103 if (*wordPtr == '\"') {
106 } else if (*wordPtr == '/') {
107 /* Skip Windows options */
108 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
110 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
114 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
117 while (*tempPtr && *tempPtr != '\"')
121 while (*tempPtr && *tempPtr != ' ')
126 command_args[num_command_args++] = wordPtr;
128 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
130 if (*wordPtr == '\"') {
138 * Now process Windows command line options
141 * Make the command-line lowercase and parse it
143 for (i = 0; i < (int)strlen(szCmdLine); i++) {
144 szCmdLine[i] = tolower(szCmdLine[i]);
147 BOOL argfound = FALSE;
148 for (i = 0; i < (int)strlen(szCmdLine); i++) {
149 if (szCmdLine[i] <= ' ') {
153 if (szCmdLine[i] == '-') {
154 while (szCmdLine[i] && szCmdLine[i] != ' ') {
162 // Now check for command-line arguments
165 // Used on NT to connect to Bacula
166 if (strncmp(&szCmdLine[i], BaculaRunServiceHelper, strlen(BaculaRunServiceHelper)) == 0) {
167 // NB : This flag MUST be parsed BEFORE "-service", otherwise it will match
168 // the wrong option! (This code should really be replaced with a simple
169 // parser machine and parse-table...)
171 // Run the Bacula Service Helper app
172 bacService::PostUserHelperMessage();
176 if (strncmp(&szCmdLine[i], BaculaRunService, strlen(BaculaRunService)) == 0) {
177 // Run Bacula as a service
178 return bacService::BaculaServiceMain();
180 // /run (this is the default if no command line arguments)
181 if (strncmp(&szCmdLine[i], BaculaRunAsUserApp, strlen(BaculaRunAsUserApp)) == 0) {
182 // Bacula is being run as a user-level program
183 return BaculaAppMain();
186 if (strncmp(&szCmdLine[i], BaculaInstallService, strlen(BaculaInstallService)) == 0) {
187 // Install Bacula as a service
188 bacService::InstallService();
189 i+=strlen(BaculaInstallService);
193 if (strncmp(&szCmdLine[i], BaculaRemoveService, strlen(BaculaRemoveService)) == 0) {
194 // Remove the Bacula service
195 bacService::RemoveService();
196 i+=strlen(BaculaRemoveService);
201 if (strncmp(&szCmdLine[i], BaculaShowAbout, strlen(BaculaShowAbout)) == 0) {
202 // Show the About dialog of an existing instance of Bacula
203 bacService::ShowAboutBox();
204 i+=strlen(BaculaShowAbout);
209 if (strncmp(&szCmdLine[i], BaculaShowStatus, strlen(BaculaShowStatus)) == 0) {
210 // Show the Status dialog of an existing instance of Bacula
211 bacService::ShowStatus();
212 i+=strlen(BaculaShowStatus);
217 if (strncmp(&szCmdLine[i], BaculaShowEvents, strlen(BaculaShowEvents)) == 0) {
218 // Show the Events dialog of an existing instance of Bacula
219 bacService::ShowEvents();
220 i+=strlen(BaculaShowEvents);
226 if (strncmp(&szCmdLine[i], BaculaKillRunningCopy, strlen(BaculaKillRunningCopy)) == 0) {
227 // Kill any already running copy of Bacula
228 bacService::KillRunningCopy();
229 i+=strlen(BaculaKillRunningCopy);
234 if (strncmp(&szCmdLine[i], BaculaShowHelp, strlen(BaculaShowHelp)) == 0) {
235 MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION);
236 i+=strlen(BaculaShowHelp);
240 MessageBox(NULL, szCmdLine, "Bad Command Line Options", MB_OK);
242 // Show the usage dialog
243 MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION);
247 // If no arguments were given then just run
256 * Called as a thread from BaculaAppMain()
257 * Here we handle the Windows messages
259 //DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
260 void *Main_Msg_Loop(LPVOID lpwThreadParam)
262 DWORD old_servicethread = g_servicethread;
265 pthread_detach(pthread_self());
267 /* Since we are the only thread with a message loop
268 * mark ourselves as the service thread so that
269 * we can receive all the window events.
271 g_servicethread = GetCurrentThreadId();
273 // Create tray icon & menu if we're running as an app
274 bacMenu *menu = new bacMenu();
276 // log_error_message("Could not create sys tray menu");
281 // Now enter the Windows message handling loop until told to quit!
283 while (GetMessage(&msg, NULL, 0,0) ) {
284 TranslateMessage(&msg);
285 DispatchMessage(&msg);
292 if (old_servicethread != 0) { /* started as NT service */
293 // Mark that we're no longer running
296 // Tell the service manager that we've stopped.
297 ReportStatus(SERVICE_STOPPED, g_error, 0);
299 pthread_kill(main_tid, SIGTERM); /* ask main thread to terminate */
301 kill(main_pid, SIGTERM); /* ask main thread to terminate */
307 * This is the main routine for Bacula when running as an application
308 * (under Windows 95 or Windows NT)
309 * Under NT, Bacula can also run as a service. The BaculaServerMain routine,
310 * defined in the bacService header, is used instead when running as a service.
317 HINSTANCE hLib = LoadLibrary("KERNEL32.DLL");
319 p_GetFileAttributesEx = (t_GetFileAttributesEx)
320 GetProcAddress(hLib, "GetFileFileAttributesExA");
321 p_SetProcessShutdownParameters = (t_SetProcessShutdownParameters)
322 GetProcAddress(hLib, "SetProcessShutdownParameters");
323 p_BackupRead = (t_BackupRead)
324 GetProcAddress(hLib, "BackupRead");
325 p_BackupWrite = (t_BackupWrite)
326 GetProcAddress(hLib, "BackupWrite");
329 hLib = LoadLibrary("ADVAPI32.DLL");
331 p_OpenProcessToken = (t_OpenProcessToken)
332 GetProcAddress(hLib, "OpenProcessToken");
333 p_AdjustTokenPrivileges = (t_AdjustTokenPrivileges)
334 GetProcAddress(hLib, "AdjustTokenPrivileges");
335 p_LookupPrivilegeValue = (t_LookupPrivilegeValue)
336 GetProcAddress(hLib, "LookupPrivilegeValueA");
341 // Set this process to be the last application to be shut down.
342 SetProcessShutdownParameters(0x100, 0);
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);
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);
355 // Call the "real" Bacula
356 BaculaMain(num_command_args, command_args);