]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/console_thread.cpp
wx-console: Improve error handling when reading configuration file.
[bacula/bacula] / bacula / src / wx-console / console_thread.cpp
1 /*
2  *
3  *    Interaction thread between director and the GUI
4  *
5  *    Nicolas Boichat, April 2004
6  *
7  *    Version $Id$
8  */
9 /*
10    Copyright (C) 2004 Kern Sibbald and John Walker
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    as published by the Free Software Foundation; either version 2
15    of the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 // http://66.102.9.104/search?q=cache:Djc1mPF3hRoJ:cvs.sourceforge.net/viewcvs.py/audacity/audacity-src/src/AudioIO.cpp%3Frev%3D1.102+macos+x+wxthread&hl=fr
28
29 #include "console_thread.h" // class's header file
30
31 #include <wx/wxprec.h>
32
33 #include <wx/thread.h>
34 #include <wx/file.h>
35 #include <bacula.h>
36 #include <jcr.h>
37
38 #include "console_conf.h"
39
40 #include "csprint.h"
41
42 #ifdef HAVE_WIN32
43 #include <windows.h>
44 DWORD  g_platform_id = VER_PLATFORM_WIN32_WINDOWS;
45 char OK_msg[]   = "2000 OK\n";
46 char TERM_msg[] = "2999 Terminate\n";
47 #endif
48
49 /* Imported functions */
50 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
51
52 bool console_thread::inited = false;
53 bool console_thread::configloaded = false;
54 wxString console_thread::working_dir = ".";
55
56 void console_thread::SetWorkingDirectory(wxString w_dir) {
57    if ((w_dir.Last() == '/') || (w_dir.Last() == '\\')) {
58       console_thread::working_dir = w_dir.Mid(0, w_dir.Length()-1);
59    }
60    else {
61       console_thread::working_dir = w_dir;
62    }
63 }
64
65 void console_thread::InitLib() {
66    if (WSA_Init() != 0) {
67       csprint("Error while initializing windows sockets...\n");
68       inited = false;
69       return;
70    }
71    
72    init_stack_dump();
73    my_name_is(0, NULL, "wx-console");
74    //textdomain("bacula-console");
75    working_directory = console_thread::working_dir;
76    
77    inited = true;
78 }
79
80 void console_thread::FreeLib() {
81    if (inited) {
82       if (WSACleanup() != 0) {
83          csprint("Error while cleaning up windows sockets...\n");
84       }
85    }
86 }
87
88 wxString errmsg;
89
90 /*
91  * Format a scanner error message
92  */
93 static void scan_err(const char *file, int line, LEX *lc, const char *msg, ...)
94 {
95    va_list arg_ptr;
96    char buf[MAXSTRING];
97    char more[MAXSTRING];
98    char err[MAXSTRING];
99    
100    va_start(arg_ptr, msg);
101    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
102    va_end(arg_ptr);
103
104    if (lc->line_no > lc->begin_line_no) {
105       bsnprintf(more, sizeof(more),
106                 _("Problem probably begins at line %d.\n"), lc->begin_line_no);
107    } else {
108       more[0] = 0;
109    }
110    bsnprintf(err, sizeof(err), _("Config error: %s\n"
111 "            : line %d, col %d of file %s\n%s\n%s"),
112       buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
113    errmsg << err; 
114 }
115
116 wxString console_thread::LoadConfig(wxString configfile) {
117    if (!inited) {
118       InitLib();
119       if (!inited)
120          return "Error while initializing library.";
121    }
122    
123    free_config_resources();
124    
125    MSGS* msgs = (MSGS *)malloc(sizeof(MSGS));
126    memset(msgs, 0, sizeof(MSGS));
127    for (int i=1; i<=M_MAX; i++) {
128 #ifndef WIN32
129       add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
130 #endif
131       add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
132       add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
133    }
134    
135    init_msg(NULL, msgs);
136    init_console_msg(console_thread::working_dir);
137
138    errmsg = "";
139    if (!parse_config(configfile.c_str(), &scan_err)) {
140       configloaded = false;
141       term_msg();
142       return errmsg;
143    }
144    
145    term_msg();
146    wxRemoveFile(console_thread::working_dir + "/wx-console.conmsg");
147    init_msg(NULL, NULL);
148    
149    configloaded = true;
150    
151    return "";
152 }
153
154 // class constructor
155 console_thread::console_thread() {
156    UA_sock = NULL;
157    choosingdirector = false;
158 }
159
160 // class destructor
161 console_thread::~console_thread() {
162    if (UA_sock) {
163       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
164       bnet_close(UA_sock);
165       UA_sock = NULL;
166    }
167 }
168
169 /*
170  * Thread entry point
171  */
172 void* console_thread::Entry() {
173    if (!inited) {
174       csprint("Error : Library not initialized\n");
175       csprint(NULL, CS_END);
176       csprint(NULL, CS_DISCONNECTED);
177       csprint(NULL, CS_TERMINATED);
178       #ifdef HAVE_WIN32
179          Exit();
180       #endif
181       return NULL;
182    }
183    
184    if (!configloaded) {
185       csprint("Error : No configuration file loaded\n");
186       csprint(NULL, CS_END);
187       csprint(NULL, CS_DISCONNECTED);
188       csprint(NULL, CS_TERMINATED);
189       #ifdef HAVE_WIN32
190          Exit();
191       #endif
192       return NULL;
193    }
194    
195    csprint("Connecting...\n");
196   
197    int count = 0;
198    DIRRES* res[16]; /* Maximum 16 directors */
199    
200    LockRes();
201    DIRRES* dir;
202    foreach_res(dir, R_DIRECTOR) {
203       res[count] = dir;
204       count++;
205       if (count == 16) {
206          break;
207       }
208    }
209    UnlockRes();
210    
211    if (count == 0) {
212       csprint("Error : No director defined in config file.\n");
213       csprint(NULL, CS_END);
214       csprint(NULL, CS_DISCONNECTED);
215       csprint(NULL, CS_TERMINATED);
216       #ifdef HAVE_WIN32
217          Exit();
218       #endif
219       return NULL;
220    }
221    else if (count == 1) {
222       directorchoosen = 1;
223    }
224    else {
225       while (true) {
226          csprint("Multiple directors found in your config file.\n");
227          for (int i = 0; i < count; i++) {
228             if (i < 9) {
229                csprint(wxString("    ") << (i+1) << ": " << res[i]->hdr.name << "\n");
230             }
231             else {
232                csprint(wxString("   ") <<  (i+1) << ": " << res[i]->hdr.name << "\n");
233             }
234          }
235          csprint(wxString("Please choose a director (1-") << count << ") : ");
236          csprint(NULL, CS_PROMPT);
237          choosingdirector = true;
238          directorchoosen = -1;
239          while(directorchoosen == -1) {
240             bmicrosleep(0, 2000);
241             Yield();
242          }      
243          choosingdirector = false;
244          if (directorchoosen != 0) {
245             break;
246          }
247       }
248    }
249
250    memset(&jcr, 0, sizeof(jcr));
251    
252    jcr.dequeuing = 1; /* TODO: catch messages */
253
254    UA_sock = bnet_connect(&jcr, 3, 3, "Director daemon",
255       res[directorchoosen-1]->address, NULL, res[directorchoosen-1]->DIRport, 0);
256       
257    if (UA_sock == NULL) {
258       csprint("Failed to connect to the director\n");
259       csprint(NULL, CS_END);
260       csprint(NULL, CS_DISCONNECTED);
261       csprint(NULL, CS_TERMINATED);
262       #ifdef HAVE_WIN32
263          Exit();
264       #endif
265       return NULL;
266    }
267
268    csprint("Connected\n");
269
270    jcr.dir_bsock = UA_sock;
271    LockRes();
272    /* If cons==NULL, default console will be used */
273    CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
274    UnlockRes();
275    if (!authenticate_director(&jcr, res[directorchoosen-1], cons)) {
276       csprint("ERR=");
277       csprint(UA_sock->msg);
278       csprint(NULL, CS_END);
279       csprint(NULL, CS_DISCONNECTED);
280       csprint(NULL, CS_TERMINATED);
281       #ifdef HAVE_WIN32
282          Exit();
283       #endif
284       return NULL;
285    }
286    
287    csprint(NULL, CS_CONNECTED);
288    
289    Write(".messages\n");
290
291    int stat;
292
293    /* main loop */
294    while(!TestDestroy()) {   /* Tests if thread has been ended */
295       if ((stat = bnet_recv(UA_sock)) >= 0) {
296          csprint(UA_sock->msg);
297       }
298       else if (stat == BNET_SIGNAL) {
299          if (UA_sock->msglen == BNET_PROMPT) {
300             csprint(NULL, CS_PROMPT);
301          }
302          else if (UA_sock->msglen == BNET_EOD) {
303             csprint(NULL, CS_END);
304          }
305          else if (UA_sock->msglen == BNET_HEARTBEAT) {
306             bnet_sig(UA_sock, BNET_HB_RESPONSE);
307             csprint("<< Heartbeat signal received, answered. >>\n", CS_DEBUG);
308          }
309          else {
310             csprint("<< Unexpected signal received : ", CS_DEBUG);
311             csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
312             csprint(">>\n", CS_DEBUG);
313          }
314       }
315       else { /* BNET_HARDEOF || BNET_ERROR */
316          csprint(NULL, CS_END);
317          break;
318       }
319            
320       if (is_bnet_stop(UA_sock)) {
321          csprint(NULL, CS_END);
322          break;            /* error or term */
323       }
324    }
325    
326    csprint(NULL, CS_DISCONNECTED);
327
328    csprint("Connection terminated\n");
329    
330    UA_sock = NULL;
331
332    csprint(NULL, CS_TERMINATED);
333
334    #ifdef HAVE_WIN32
335       Exit();
336    #endif
337    
338    return NULL;
339 }
340
341 void console_thread::Write(const char* str) {
342    if (UA_sock) {
343        UA_sock->msglen = strlen(str);
344        pm_strcpy(&UA_sock->msg, str);
345        bnet_send(UA_sock);
346    }
347    else if (choosingdirector) {
348       wxString number = str;
349       number.RemoveLast(); /* Removes \n */
350       long val;
351       if (number.ToLong(&val)) {
352          directorchoosen = (int)val;
353       }
354       else {
355          directorchoosen = 0;
356       }
357    }
358 }
359
360 void console_thread::Delete() {
361    Write("quit\n");
362    if (UA_sock) {
363       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
364       bnet_close(UA_sock);
365       UA_sock = NULL;
366       /*csprint(NULL, CS_END);
367       csprint(NULL, CS_DISCONNECTED);
368       csprint(NULL, CS_TERMINATED);*/
369    }
370 }