2 This file is patterned after the VNC Win32 code by ATT
5 Bacula® - The Network Backup Solution
7 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
9 The main author of Bacula is Kern Sibbald, with contributions from
10 many others, a complete list can be found in the file AUTHORS.
11 This program is Free Software; you can redistribute it and/or
12 modify it under the terms of version two of the GNU General Public
13 License as published by the Free Software Foundation plus additions
14 that are listed in the file LICENSE.
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 Bacula® is a registered trademark of John Walker.
27 The licensor of Bacula is the Free Software Foundation Europe
28 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
29 Switzerland, email:ftf@fsfeurope.org.
36 #include "winbacula.h"
38 #include "winservice.h"
43 #define _WIN32_IE 0x0401
45 #define _WIN32_WINNT 0x0501
48 extern int BaculaMain(int argc, char *argv[]);
49 extern void terminate_filed(int sig);
51 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
52 extern void d_msg(const char *, int, int, const char *, ...);
53 extern void VSSInit();
56 HINSTANCE hAppInstance;
57 const char *szAppName = "Bacula-fd";
59 bool opt_debug = false;
61 /* Imported variables */
62 extern DWORD g_servicethread;
64 #define MAX_COMMAND_ARGS 100
65 static char *command_args[MAX_COMMAND_ARGS] = {"bacula-fd", NULL};
66 static int num_command_args = 1;
67 static pid_t main_pid;
68 static pthread_t main_tid;
71 * WinMain parses the command line and either calls the main App
72 * routine or, under NT, the main service routine.
74 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
75 PSTR CmdLine, int iCmdShow)
77 char *szCmdLine = CmdLine;
78 char *wordPtr, *tempPtr;
81 /* Save the application instance and main thread id */
82 hAppInstance = hInstance;
83 mainthreadId = GetCurrentThreadId();
86 main_tid = pthread_self();
88 INITCOMMONCONTROLSEX initCC = {
89 sizeof(INITCOMMONCONTROLSEX),
93 InitCommonControlsEx(&initCC);
96 * Funny things happen with the command line if the
97 * execution comes from c:/Program Files/bacula/bacula.exe
98 * We get a command line like: Files/bacula/bacula.exe" options
99 * I.e. someone stops scanning command line on a space, not
100 * realizing that the filename is quoted!!!!!!!!!!
101 * So if first character is not a double quote and
102 * the last character before first space is a double
103 * quote, we throw away the junk.
107 while (*wordPtr && *wordPtr != ' ')
109 if (wordPtr > szCmdLine) /* backup to char before space */
111 /* if first character is not a quote and last is, junk it */
112 if (*szCmdLine != '"' && *wordPtr == '"') {
113 szCmdLine = wordPtr + 1;
116 /* Build Unix style argc *argv[] */
118 /* Don't NULL command_args[0] !!! */
119 for (i=1;i<MAX_COMMAND_ARGS;i++)
120 command_args[i] = NULL;
122 char *pszArgs = bstrdup(szCmdLine);
125 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
127 if (*wordPtr == '\"') {
130 } else if (*wordPtr == '/') {
131 /* Skip Windows options */
132 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
134 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
138 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
141 while (*tempPtr && *tempPtr != '\"')
145 while (*tempPtr && *tempPtr != ' ')
150 command_args[num_command_args++] = wordPtr;
152 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
154 if (*wordPtr == '\"') {
162 * Now process Windows command line options
164 for (i = 0; i < (int)strlen(szCmdLine); i++) {
165 if (szCmdLine[i] <= ' ') {
169 if (szCmdLine[i] != '/') {
173 /* Now check for command-line arguments */
175 /* /debug - enable debugging facilities such as console message window */
176 if (strnicmp(&szCmdLine[i], BaculaOptDebug, sizeof(BaculaOptDebug) - 1) == 0) {
178 i += sizeof(BaculaOptDebug) - 1;
182 /* /service start service */
183 if (strnicmp(&szCmdLine[i], BaculaRunService, sizeof(BaculaRunService) - 1) == 0) {
184 /* Run Bacula as a service */
185 return bacService::BaculaServiceMain();
187 /* /run (this is the default if no command line arguments) */
188 if (strnicmp(&szCmdLine[i], BaculaRunAsUserApp, sizeof(BaculaRunAsUserApp) - 1) == 0) {
189 /* Bacula is being run as a user-level program */
190 return BaculaAppMain();
193 if (strnicmp(&szCmdLine[i], BaculaInstallService, sizeof(BaculaInstallService) - 1) == 0) {
194 /* Install Bacula as a service */
195 return bacService::InstallService(&szCmdLine[i + sizeof(BaculaInstallService) - 1]);
198 if (strnicmp(&szCmdLine[i], BaculaRemoveService, sizeof(BaculaRemoveService) - 1) == 0) {
199 /* Remove the Bacula service */
200 return bacService::RemoveService();
204 if (strnicmp(&szCmdLine[i], BaculaShowAbout, sizeof(BaculaShowAbout) - 1) == 0) {
205 /* Show Bacula's about box */
206 return bacService::ShowAboutBox();
210 if (strnicmp(&szCmdLine[i], BaculaShowStatus, sizeof(BaculaShowStatus) - 1) == 0) {
211 /* Show Bacula's status box */
212 return bacService::ShowStatus();
216 if (strnicmp(&szCmdLine[i], BaculaKillRunningCopy, sizeof(BaculaKillRunningCopy) - 1) == 0) {
217 /* Kill running copy of Bacula */
218 return bacService::KillRunningCopy();
222 if (strnicmp(&szCmdLine[i], BaculaShowHelp, sizeof(BaculaShowHelp) - 1) == 0) {
223 MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK|MB_ICONINFORMATION);
227 MessageBox(NULL, szCmdLine, _("Bad Command Line Options"), MB_OK);
229 /* Show the usage dialog */
230 MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK | MB_ICONINFORMATION);
235 return BaculaAppMain();
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;
248 pthread_detach(pthread_self());
250 /* Since we are the only thread with a message loop
251 * mark ourselves as the service thread so that
252 * we can receive all the window events.
254 g_servicethread = GetCurrentThreadId();
256 /* Create tray icon & menu if we're running as an app */
257 bacMenu *menu = new bacMenu();
259 // log_error_message("Could not create sys tray menu");
263 /* Now enter the Windows message handling loop until told to quit! */
265 while (GetMessage(&msg, NULL, 0,0) ) {
266 TranslateMessage(&msg);
267 DispatchMessage(&msg);
274 if (old_servicethread != 0) { /* started as NT service */
275 /* Mark that we're no longer running */
278 /* Tell the service manager that we've stopped. */
279 ReportStatus(SERVICE_STOPPED, g_error, 0);
281 /* Tell main program to go away */
284 /* Should not get here */
285 pthread_kill(main_tid, SIGTERM); /* ask main thread to terminate */
287 kill(main_pid, SIGTERM); /* ask main thread to terminate */
293 * This is the main routine for Bacula when running as an application
294 * (under Windows 95 or Windows NT)
295 * Under NT, Bacula can also run as a service. The BaculaServerMain routine,
296 * defined in the bacService header, is used instead when running as a service.
300 /* DWORD dwThreadID; */
302 DWORD dwCharsWritten;
306 /* If no arguments were given then just run */
307 if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
312 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
318 /* Set this process to be the last application to be shut down. */
319 if (p_SetProcessShutdownParameters) {
320 p_SetProcessShutdownParameters(0x100, 0);
323 HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
324 if (hservwnd != NULL) {
325 /* We don't allow multiple instances! */
326 MessageBox(NULL, _("Another instance of Bacula is already running"), szAppName, MB_OK);
330 /* Create a thread to handle the Windows messages */
331 pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0);
333 /* Call the "real" Bacula */
334 BaculaMain(num_command_args, command_args);