2 Copyright (C) 2000-2005 Kern Sibbald
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
30 #include "winbacula.h"
32 #include "winservice.h"
35 #include "../../findlib/winapi.h"
37 extern int BaculaMain(int argc, char *argv[]);
38 extern void terminate_filed(int sig);
40 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
41 extern void d_msg(const char *, int, int, const char *, ...);
44 HINSTANCE hAppInstance;
45 const char *szAppName = "Bacula";
48 /* Imported variables */
49 extern DWORD g_servicethread;
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;
58 * WinMain parses the command line and either calls the main App
59 * routine or, under NT, the main service routine.
61 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
62 PSTR CmdLine, int iCmdShow)
64 char *szCmdLine = CmdLine;
65 char *wordPtr, *tempPtr;
68 /* Save the application instance and main thread id */
69 hAppInstance = hInstance;
70 mainthreadId = GetCurrentThreadId();
73 main_tid = pthread_self();
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.
87 while (*wordPtr && *wordPtr != ' ')
89 if (wordPtr > szCmdLine) /* backup to char before space */
91 /* if first character is not a quote and last is, junk it */
92 if (*szCmdLine != '"' && *wordPtr == '"') {
93 szCmdLine = wordPtr + 1;
95 // MessageBox(NULL, szCmdLine, "Cmdline", MB_OK);
97 /* Build Unix style argc *argv[] */
99 /* Don't NULL command_args[0] !!! */
100 for (i=1;i<MAX_COMMAND_ARGS;i++)
101 command_args[i] = NULL;
105 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
107 if (*wordPtr == '\"') {
110 } else if (*wordPtr == '/') {
111 /* Skip Windows options */
112 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
114 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
118 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
121 while (*tempPtr && *tempPtr != '\"')
125 while (*tempPtr && *tempPtr != ' ')
130 command_args[num_command_args++] = wordPtr;
132 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
134 if (*wordPtr == '\"') {
142 * Now process Windows command line options
145 * Make the command-line lowercase and parse it
147 for (i = 0; i < (int)strlen(szCmdLine); i++) {
148 szCmdLine[i] = tolower(szCmdLine[i]);
151 bool argfound = false;
152 for (i = 0; i < (int)strlen(szCmdLine); i++) {
153 if (szCmdLine[i] <= ' ') {
157 if (szCmdLine[i] == '-') {
158 while (szCmdLine[i] && szCmdLine[i] != ' ') {
166 /* Now check for command-line arguments */
168 /* /service start service */
169 if (strncmp(&szCmdLine[i], BaculaRunService, strlen(BaculaRunService)) == 0) {
170 /* Run Bacula as a service */
171 return bacService::BaculaServiceMain();
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();
179 if (strncmp(&szCmdLine[i], BaculaInstallService, strlen(BaculaInstallService)) == 0) {
180 /* Install Bacula as a service */
181 bacService::InstallService();
182 i += strlen(BaculaInstallService);
186 if (strncmp(&szCmdLine[i], BaculaRemoveService, strlen(BaculaRemoveService)) == 0) {
187 /* Remove the Bacula service */
188 bacService::RemoveService();
189 i += strlen(BaculaRemoveService);
194 if (strncmp(&szCmdLine[i], BaculaShowAbout, strlen(BaculaShowAbout)) == 0) {
195 /* Show Bacula's about box */
196 bacService::ShowAboutBox();
197 i += strlen(BaculaShowAbout);
202 if (strncmp(&szCmdLine[i], BaculaShowStatus, strlen(BaculaShowStatus)) == 0) {
203 /* Show Bacula's status box */
204 bacService::ShowStatus();
205 i += strlen(BaculaShowStatus);
210 if (strncmp(&szCmdLine[i], BaculaKillRunningCopy, strlen(BaculaKillRunningCopy)) == 0) {
211 /* Kill running copy of Bacula */
212 bacService::KillRunningCopy();
213 i += strlen(BaculaKillRunningCopy);
218 if (strncmp(&szCmdLine[i], BaculaShowHelp, strlen(BaculaShowHelp)) == 0) {
219 MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK|MB_ICONINFORMATION);
220 i += strlen(BaculaShowHelp);
224 MessageBox(NULL, szCmdLine, "Bad Command Line Options", MB_OK);
226 /* Show the usage dialog */
227 MessageBox(NULL, BaculaUsageText, "Bacula Usage", MB_OK | MB_ICONINFORMATION);
231 /* If no arguments were given then just run */
240 * Called as a thread from BaculaAppMain()
241 * Here we handle the Windows messages
243 //DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
244 void *Main_Msg_Loop(LPVOID lpwThreadParam)
246 DWORD old_servicethread = g_servicethread;
249 pthread_detach(pthread_self());
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.
255 g_servicethread = GetCurrentThreadId();
257 /* Create tray icon & menu if we're running as an app */
258 bacMenu *menu = new bacMenu();
260 // log_error_message("Could not create sys tray menu");
265 /* Now enter the Windows message handling loop until told to quit! */
267 while (GetMessage(&msg, NULL, 0,0) ) {
268 TranslateMessage(&msg);
269 DispatchMessage(&msg);
276 if (old_servicethread != 0) { /* started as NT service */
277 /* Mark that we're no longer running */
280 /* Tell the service manager that we've stopped. */
281 ReportStatus(SERVICE_STOPPED, g_error, 0);
283 /* Tell main program to go away */
286 /* Should not get here */
287 pthread_kill(main_tid, SIGTERM); /* ask main thread to terminate */
289 kill(main_pid, SIGTERM); /* ask main thread to terminate */
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.
302 /* DWORD dwThreadID; */
305 HINSTANCE hLib = LoadLibrary("KERNEL32.DLL");
307 p_GetFileAttributesExA = (t_GetFileAttributesExA)
308 GetProcAddress(hLib, "GetFileAttributesExA");
309 p_GetFileAttributesExW = (t_GetFileAttributesExW)
310 GetProcAddress(hLib, "GetFileAttributesExW");
311 p_SetProcessShutdownParameters = (t_SetProcessShutdownParameters)
312 GetProcAddress(hLib, "SetProcessShutdownParameters");
313 p_BackupRead = (t_BackupRead)
314 GetProcAddress(hLib, "BackupRead");
315 p_BackupWrite = (t_BackupWrite)
316 GetProcAddress(hLib, "BackupWrite");
319 hLib = LoadLibrary("ADVAPI32.DLL");
321 p_OpenProcessToken = (t_OpenProcessToken)
322 GetProcAddress(hLib, "OpenProcessToken");
323 p_AdjustTokenPrivileges = (t_AdjustTokenPrivileges)
324 GetProcAddress(hLib, "AdjustTokenPrivileges");
325 p_LookupPrivilegeValue = (t_LookupPrivilegeValue)
326 GetProcAddress(hLib, "LookupPrivilegeValueA");
330 * Even if these are defined, don't use on old
333 if (bacService::IsWin95()) {
335 p_BackupWrite = NULL;
338 /* Set this process to be the last application to be shut down. */
339 if (p_SetProcessShutdownParameters) {
340 p_SetProcessShutdownParameters(0x100, 0);
343 HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
344 if (hservwnd != NULL) {
345 /* We don't allow multiple instances! */
346 MessageBox(NULL, "Another instance of Bacula is already running", szAppName, MB_OK);
350 /* Create a thread to handle the Windows messages */
351 // (void)CreateThread(NULL, 0, Main_Msg_Loop, NULL, 0, &dwThreadID);
352 pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0);
354 /* Call the "real" Bacula */
355 BaculaMain(num_command_args, command_args);