2 Copyright (C) 2000-2006 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
6 version 2 as amended with additional clauses defined in the
7 file LICENSE in the main source directory.
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
12 the file LICENSE for additional details.
14 This file is patterned after the VNC Win32 code by ATT
22 #include "winbacula.h"
24 #include "winservice.h"
29 #define _WIN32_IE 0x0401
31 #define _WIN32_WINNT 0x0501
34 extern int BaculaMain(int argc, char *argv[]);
35 extern void terminate_filed(int sig);
37 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
38 extern void d_msg(const char *, int, int, const char *, ...);
39 extern void VSSInit();
42 HINSTANCE hAppInstance;
43 const char *szAppName = "Bacula-fd";
45 bool opt_debug = false;
47 /* Imported variables */
48 extern DWORD g_servicethread;
50 #define MAX_COMMAND_ARGS 100
51 static char *command_args[MAX_COMMAND_ARGS] = {"bacula-fd", NULL};
52 static int num_command_args = 1;
53 static pid_t main_pid;
54 static pthread_t main_tid;
57 * WinMain parses the command line and either calls the main App
58 * routine or, under NT, the main service routine.
60 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
61 PSTR CmdLine, int iCmdShow)
63 char *szCmdLine = CmdLine;
64 char *wordPtr, *tempPtr;
67 /* Save the application instance and main thread id */
68 hAppInstance = hInstance;
69 mainthreadId = GetCurrentThreadId();
72 main_tid = pthread_self();
74 INITCOMMONCONTROLSEX initCC = {
75 sizeof(INITCOMMONCONTROLSEX),
79 InitCommonControlsEx(&initCC);
82 * Funny things happen with the command line if the
83 * execution comes from c:/Program Files/bacula/bacula.exe
84 * We get a command line like: Files/bacula/bacula.exe" options
85 * I.e. someone stops scanning command line on a space, not
86 * realizing that the filename is quoted!!!!!!!!!!
87 * So if first character is not a double quote and
88 * the last character before first space is a double
89 * quote, we throw away the junk.
93 while (*wordPtr && *wordPtr != ' ')
95 if (wordPtr > szCmdLine) /* backup to char before space */
97 /* if first character is not a quote and last is, junk it */
98 if (*szCmdLine != '"' && *wordPtr == '"') {
99 szCmdLine = wordPtr + 1;
102 /* Build Unix style argc *argv[] */
104 /* Don't NULL command_args[0] !!! */
105 for (i=1;i<MAX_COMMAND_ARGS;i++)
106 command_args[i] = NULL;
108 char *pszArgs = bstrdup(szCmdLine);
111 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
113 if (*wordPtr == '\"') {
116 } else if (*wordPtr == '/') {
117 /* Skip Windows options */
118 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
120 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
124 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
127 while (*tempPtr && *tempPtr != '\"')
131 while (*tempPtr && *tempPtr != ' ')
136 command_args[num_command_args++] = wordPtr;
138 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
140 if (*wordPtr == '\"') {
148 * Now process Windows command line options
150 for (i = 0; i < (int)strlen(szCmdLine); i++) {
151 if (szCmdLine[i] <= ' ') {
155 if (szCmdLine[i] != '/') {
159 /* Now check for command-line arguments */
161 /* /debug - enable debugging facilities such as console message window */
162 if (strnicmp(&szCmdLine[i], BaculaOptDebug, sizeof(BaculaOptDebug) - 1) == 0) {
164 i += sizeof(BaculaOptDebug) - 1;
168 /* /service start service */
169 if (strnicmp(&szCmdLine[i], BaculaRunService, sizeof(BaculaRunService) - 1) == 0) {
170 /* Run Bacula as a service */
171 return bacService::BaculaServiceMain();
173 /* /run (this is the default if no command line arguments) */
174 if (strnicmp(&szCmdLine[i], BaculaRunAsUserApp, sizeof(BaculaRunAsUserApp) - 1) == 0) {
175 /* Bacula is being run as a user-level program */
176 return BaculaAppMain();
179 if (strnicmp(&szCmdLine[i], BaculaInstallService, sizeof(BaculaInstallService) - 1) == 0) {
180 /* Install Bacula as a service */
181 return bacService::InstallService(&szCmdLine[i + sizeof(BaculaInstallService) - 1]);
184 if (strnicmp(&szCmdLine[i], BaculaRemoveService, sizeof(BaculaRemoveService) - 1) == 0) {
185 /* Remove the Bacula service */
186 return bacService::RemoveService();
190 if (strnicmp(&szCmdLine[i], BaculaShowAbout, sizeof(BaculaShowAbout) - 1) == 0) {
191 /* Show Bacula's about box */
192 return bacService::ShowAboutBox();
196 if (strnicmp(&szCmdLine[i], BaculaShowStatus, sizeof(BaculaShowStatus) - 1) == 0) {
197 /* Show Bacula's status box */
198 return bacService::ShowStatus();
202 if (strnicmp(&szCmdLine[i], BaculaKillRunningCopy, sizeof(BaculaKillRunningCopy) - 1) == 0) {
203 /* Kill running copy of Bacula */
204 return bacService::KillRunningCopy();
208 if (strnicmp(&szCmdLine[i], BaculaShowHelp, sizeof(BaculaShowHelp) - 1) == 0) {
209 MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK|MB_ICONINFORMATION);
213 MessageBox(NULL, szCmdLine, _("Bad Command Line Options"), MB_OK);
215 /* Show the usage dialog */
216 MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK | MB_ICONINFORMATION);
221 return BaculaAppMain();
226 * Called as a thread from BaculaAppMain()
227 * Here we handle the Windows messages
229 //DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
230 void *Main_Msg_Loop(LPVOID lpwThreadParam)
232 DWORD old_servicethread = g_servicethread;
234 pthread_detach(pthread_self());
236 /* Since we are the only thread with a message loop
237 * mark ourselves as the service thread so that
238 * we can receive all the window events.
240 g_servicethread = GetCurrentThreadId();
242 /* Create tray icon & menu if we're running as an app */
243 bacMenu *menu = new bacMenu();
245 // log_error_message("Could not create sys tray menu");
249 /* Now enter the Windows message handling loop until told to quit! */
251 while (GetMessage(&msg, NULL, 0,0) ) {
252 TranslateMessage(&msg);
253 DispatchMessage(&msg);
260 if (old_servicethread != 0) { /* started as NT service */
261 /* Mark that we're no longer running */
264 /* Tell the service manager that we've stopped. */
265 ReportStatus(SERVICE_STOPPED, g_error, 0);
267 /* Tell main program to go away */
270 /* Should not get here */
271 pthread_kill(main_tid, SIGTERM); /* ask main thread to terminate */
273 kill(main_pid, SIGTERM); /* ask main thread to terminate */
279 * This is the main routine for Bacula when running as an application
280 * (under Windows 95 or Windows NT)
281 * Under NT, Bacula can also run as a service. The BaculaServerMain routine,
282 * defined in the bacService header, is used instead when running as a service.
286 /* DWORD dwThreadID; */
288 DWORD dwCharsWritten;
292 /* If no arguments were given then just run */
293 if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
298 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
304 /* Set this process to be the last application to be shut down. */
305 if (p_SetProcessShutdownParameters) {
306 p_SetProcessShutdownParameters(0x100, 0);
309 HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
310 if (hservwnd != NULL) {
311 /* We don't allow multiple instances! */
312 MessageBox(NULL, _("Another instance of Bacula is already running"), szAppName, MB_OK);
316 /* Create a thread to handle the Windows messages */
317 pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0);
319 /* Call the "real" Bacula */
320 BaculaMain(num_command_args, command_args);