]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/dird/winmain.cpp
kes Reapply my bat.conf install script in qt-console. I think I
[bacula/bacula] / bacula / src / win32 / dird / winmain.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28
29 #include <unistd.h>
30 #include <ctype.h>
31
32 #include "bacula.h"
33 #include "winbacula.h"
34 #include "winservice.h"
35 #include <signal.h>
36 #include <pthread.h>
37
38 extern int BaculaMain(int argc, char *argv[]);
39 extern void terminate_dird(int sig);
40 extern DWORD g_error;
41 extern BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
42 extern void d_msg(const char *, int, int, const char *, ...);
43
44 /* Globals */
45 HINSTANCE      hAppInstance;
46 const char     *szAppName = "Bacula-dir";
47 DWORD          mainthreadId;
48 bool           opt_debug = false;
49
50 /* Imported variables */
51 extern DWORD    g_servicethread;
52
53 #define MAX_COMMAND_ARGS 100
54 static char *command_args[MAX_COMMAND_ARGS] = {"bacula-dir", NULL};
55 static int num_command_args = 1;
56 static pid_t main_pid;
57 static pthread_t main_tid;
58
59 /*
60  * WinMain parses the command line and either calls the main App
61  * routine or, under NT, the main service routine.
62  */
63 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
64                    PSTR CmdLine, int iCmdShow)
65 {
66    char *szCmdLine = CmdLine;
67    char *wordPtr, *tempPtr;
68    int i, quote;
69
70    /* Save the application instance and main thread id */
71    hAppInstance = hInstance;
72    mainthreadId = GetCurrentThreadId();
73
74    main_pid = getpid();
75    main_tid = pthread_self();
76
77    /*
78     * Funny things happen with the command line if the
79     * execution comes from c:/Program Files/bacula/bacula.exe
80     * We get a command line like: Files/bacula/bacula.exe" options
81     * I.e. someone stops scanning command line on a space, not
82     * realizing that the filename is quoted!!!!!!!!!!
83     * So if first character is not a double quote and
84     * the last character before first space is a double
85     * quote, we throw away the junk.
86     */
87
88    wordPtr = szCmdLine;
89    while (*wordPtr && *wordPtr != ' ')
90       wordPtr++;
91    if (wordPtr > szCmdLine)      /* backup to char before space */
92       wordPtr--;
93    /* if first character is not a quote and last is, junk it */
94    if (*szCmdLine != '"' && *wordPtr == '"') {
95       szCmdLine = wordPtr + 1;
96    }
97
98    /* Build Unix style argc *argv[] */      
99
100    /* Don't NULL command_args[0] !!! */
101    for (i=1;i<MAX_COMMAND_ARGS;i++)
102       command_args[i] = NULL;
103
104    char *pszArgs = bstrdup(szCmdLine);
105    wordPtr = pszArgs;
106    quote = 0;
107    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
108       wordPtr++;
109    if (*wordPtr == '\"') {
110       quote = 1;
111       wordPtr++;
112    } else if (*wordPtr == '/') {
113       /* Skip Windows options */
114       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
115          wordPtr++;
116       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
117          wordPtr++;
118    }
119    if (*wordPtr) {
120       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
121          tempPtr = wordPtr;
122          if (quote) {
123             while (*tempPtr && *tempPtr != '\"')
124                tempPtr++;
125             quote = 0;
126          } else {
127             while (*tempPtr && *tempPtr != ' ')
128             tempPtr++;
129          }
130          if (*tempPtr)
131             *(tempPtr++) = '\0';
132          command_args[num_command_args++] = wordPtr;
133          wordPtr = tempPtr;
134          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
135             wordPtr++;
136          if (*wordPtr == '\"') {
137             quote = 1;
138             wordPtr++;
139          }
140       }
141    }
142
143    /*
144     * Now process Windows command line options
145     */
146    for (i = 0; i < (int)strlen(szCmdLine); i++) {
147       if (szCmdLine[i] <= ' ') {
148          continue;
149       }
150
151       if (szCmdLine[i] != '/') {
152          break;
153       }
154
155       /* Now check for command-line arguments */
156
157       /* /debug install quietly -- no prompts */
158       if (strnicmp(&szCmdLine[i], BaculaOptDebug, sizeof(BaculaOptDebug) - 1) == 0) {
159          opt_debug = true;
160          i += sizeof(BaculaOptDebug) - 1;
161          continue;
162       }
163
164       /* /service start service */
165       if (strnicmp(&szCmdLine[i], BaculaRunService, sizeof(BaculaRunService) - 1) == 0) {
166          /* Run Bacula as a service */
167          return bacService::BaculaServiceMain();
168       }
169       /* /run  (this is the default if no command line arguments) */
170       if (strnicmp(&szCmdLine[i], BaculaRunAsUserApp, sizeof(BaculaRunAsUserApp) - 1) == 0) {
171          /* Bacula is being run as a user-level program */
172          return BaculaAppMain();
173       }
174       /* /install */
175       if (strnicmp(&szCmdLine[i], BaculaInstallService, sizeof(BaculaInstallService) - 1) == 0) {
176          /* Install Bacula as a service */
177          return bacService::InstallService(&szCmdLine[i + sizeof(BaculaInstallService) - 1]);
178       }
179       /* /remove */
180       if (strnicmp(&szCmdLine[i], BaculaRemoveService, sizeof(BaculaRemoveService) - 1) == 0) {
181          /* Remove the Bacula service */
182          return bacService::RemoveService();
183       }
184
185       /* /kill */
186       if (strnicmp(&szCmdLine[i], BaculaKillRunningCopy, sizeof(BaculaKillRunningCopy) - 1) == 0) {
187          /* Kill running copy of Bacula */
188          return bacService::KillRunningCopy() ? 0 : 1;
189       }
190
191       /* /help */
192       if (strnicmp(&szCmdLine[i], BaculaShowHelp, sizeof(BaculaShowHelp) - 1) == 0) {
193          MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK|MB_ICONINFORMATION);
194          return 0;
195       }
196       
197       MessageBox(NULL, szCmdLine, _("Bad Command Line Options"), MB_OK);
198
199       /* Show the usage dialog */
200       MessageBox(NULL, BaculaUsageText, _("Bacula Usage"), MB_OK | MB_ICONINFORMATION);
201       return 1;
202    }
203
204    return BaculaAppMain();
205 }
206
207
208 /*
209  * Called as a thread from BaculaAppMain()
210  * Here we handle the Windows messages
211  */
212 //DWORD WINAPI Main_Msg_Loop(LPVOID lpwThreadParam)
213 void *Main_Msg_Loop(LPVOID lpwThreadParam) 
214 {
215    DWORD old_servicethread = g_servicethread;
216
217    pthread_detach(pthread_self());
218
219    /* Since we are the only thread with a message loop
220     * mark ourselves as the service thread so that
221     * we can receive all the window events.
222     */
223    g_servicethread = GetCurrentThreadId();
224
225    /* Now enter the Windows message handling loop until told to quit! */
226    MSG msg;
227    while (GetMessage(&msg, NULL, 0,0) ) {
228       TranslateMessage(&msg);
229       DispatchMessage(&msg);
230    }
231
232    if (old_servicethread != 0) { /* started as NT service */
233       /* Mark that we're no longer running */
234       g_servicethread = 0;
235
236       /* Tell the service manager that we've stopped. */
237       ReportStatus(SERVICE_STOPPED, g_error, 0);
238    }  
239    /* Tell main program to go away */
240    terminate_dird(0);
241
242    /* Should not get here */
243    pthread_kill(main_tid, SIGTERM);   /* ask main thread to terminate */
244    sleep(1);
245    kill(main_pid, SIGTERM);           /* ask main thread to terminate */
246    _exit(0);
247 }
248  
249
250 /*
251  * This is the main routine for Bacula when running as an application
252  * (under Windows 95 or Windows NT)
253  * Under NT, Bacula can also run as a service.  The BaculaServerMain routine,
254  * defined in the bacService header, is used instead when running as a service.
255  */
256 int BaculaAppMain()
257 {
258  /* DWORD dwThreadID; */
259    pthread_t tid;
260    DWORD dwCharsWritten;
261
262    InitWinAPIWrapper();
263
264    WSA_Init();
265
266    /* If no arguments were given then just run */
267    if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
268       if (opt_debug) {
269          AllocConsole();
270       }
271    }
272    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
273
274    /* Set this process to be the last application to be shut down. */
275    if (p_SetProcessShutdownParameters) {
276       p_SetProcessShutdownParameters(0x100, 0);
277    }
278
279    /* Create a thread to handle the Windows messages */
280    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
281
282    /* Call the "real" Bacula */
283    BaculaMain(num_command_args, command_args);
284    PostQuitMessage(0);
285    WSACleanup();
286    _exit(0);
287 }