source: MondoRescue/branches/2.05/mondo/mondo/xmondo/xmondorestore.cpp@ 2708

Last change on this file since 2708 was 2708, checked in by Bruno Cornec, 13 years ago

r4184@localhost: bruno | 2011-01-27 15:52:51 +0100

  • Adds support for hpsa driver (new HP Smart Array driver)
  • Property svn:keywords set to Id
File size: 17.8 KB
RevLine 
[1]1/***************************************************************************
2 xmondorestore.cpp - restore functions
3 -------------------------------------
4 begin : Sun Nov 22 2003
5 copyright : (C) 2003 by Joshua Oreman
6 email : oremanj@get-linux.org
[2708]7 cvsid : $Id: xmondorestore.cpp 2708 2011-01-27 18:31:44Z bruno $
[1]8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19#include <qbuttongroup.h>
20#include <qlineedit.h>
21#include <qlabel.h>
22#include <qlayout.h>
23#include <qlistview.h>
24#include <qstringlist.h>
25#include <qmessagebox.h>
26
27#include "xmondo.h"
28#include "xmondorestore.h"
29#include <X-specific.h>
30extern "C" {
31#define bool int
32#include <libmondo-devices-EXT.h>
33#include <libmondo-filelist-EXT.h>
34#include <libmondo-files-EXT.h>
35#include <libmondo-fork-EXT.h>
36#include <libmondo-tools-EXT.h>
37#undef bool
38 int restore_everything (struct s_bkpinfo *bkpinfo, struct s_node *filelist);
39 int get_cfg_file_from_archive (struct s_bkpinfo *bkpinfo);
40 int read_cfg_file_into_bkpinfo (char *cfg_file, struct s_bkpinfo *bkpinfo);
41 int mount_cdrom (struct s_bkpinfo *bkpinfo);
42 void setup_MR_global_filenames (struct s_bkpinfo *bkpinfo);
43 extern char *g_mondo_cfg_file;
44 extern char *g_filelist_full;
45 extern int g_current_media_number;
46 extern int g_text_mode;
47}
48
49extern QProgressBar *XMondoProgress;
50extern QLabel *XMondoProgressWhat, *XMondoProgressWhat2, *XMondoProgressWhat3;
51extern QCheckBox *XMondoVerbose;
52extern QMultiLineEdit *XMondoLog;
53extern QLabel *XMondoStatus;
54extern QLabel *XMondoTimeTaken, *XMondoTimeToGo, *XMondoProgressPercent;
55extern QPushButton *XMondoCancel;
56extern XMEventHolder events;
57
58class XMCheckListItem : public QCheckListItem
59{
60public:
61 XMCheckListItem (QCheckListItem * parent, const QString & text, Type tt = CheckBox)
62 : QCheckListItem (parent, text, tt), _text (text)
63 {
64 }
65
66 XMCheckListItem (QListViewItem * parent, const QString & text, Type tt = CheckBox)
67 : QCheckListItem (parent, text, tt), _text (text)
68 {
69 }
70
71 XMCheckListItem (QListView * parent, const QString & text, Type tt = CheckBox)
72 : QCheckListItem (parent, text, tt), _text (text)
73 {
74 }
75
76 virtual ~XMCheckListItem() {}
77
78 virtual int rtti() { return 1001; }
79
80 virtual void setOn (bool on) {
81 QCheckListItem::setOn (on);
82 }
83
84 static QLabel *progressDisplay;
85 static bool *doneSetup;
86 static bool selecting;
87 static int counter;
88 static int depth;
89
90protected:
91 virtual void stateChange (bool on) {
92 if (firstChild()) {
93 if (!selecting) {
94 progressDisplay->setText (QString ("%1electing %2...").arg (on? "S" : "Des").arg (_text));
95 counter = depth = 0;
96 selecting = true;
97 if (doneSetup) *doneSetup = false;
98 }
99
100 for (QListViewItem *lvi = firstChild(); lvi; lvi = lvi->nextSibling()) {
101 XMCheckListItem *cli;
102 if ((cli = dynamic_cast <XMCheckListItem *> (lvi)) != 0) {
103 if (!(++counter % 10000)) {
104 progressDisplay->setText (progressDisplay->text() + ".");
105 }
106 if (!(counter % 1000)) {
107 kapp->processEvents();
108 }
109 depth++;
110 cli->setOn (on);
111 depth--;
112 }
113 }
114
115 if (depth == 0) {
116 selecting = false;
117 progressDisplay->setText ("Please select files and directories to be restored.");
118 if (doneSetup) *doneSetup = true;
119 }
120 }
121 }
122
123private:
124 // Ugly hack, but it works: fix segfault
125 QString _text;
126};
127
128QLabel *XMCheckListItem::progressDisplay = 0;
129bool XMCheckListItem::selecting = false;
130bool *XMCheckListItem::doneSetup = 0;
131int XMCheckListItem::counter = 0;
132int XMCheckListItem::depth = 0;
133
134struct XM_node
135{
136 QString s;
137 XM_node *firstChild;
138 XM_node *nextSibling;
139};
140
141#define XMLF_OK 0
142#define XMLF_CANTOPEN 1
143
144// Requirements:
145// - File must be sorted
146// - Entry for a directory must come directly before entries for its files
147void XM_load_filelist_sub (FILE *fp, QStringList first, XMCheckListItem *top, QLabel *status, int numlines)
148{
149 static int depth = 0;
150 static int lino = 0;
151 bool tristated = false;
152
153 char line[4095];
154 while (fgets (line, 4095, fp)) {
155 bool chomped = false;
156
157 if (line[strlen (line) - 1] == '\n') {
158 line[strlen (line) - 1] = 0;
159 chomped = true;
160 }
161
162 QStringList dirComponents = QStringList::split ("/", line);
163 if (dirComponents.size() == 0) continue;
164 if (depth > 0) {
165 bool good = true;
166 for (int i = 0; (i < dirComponents.size()) && (i < first.size()) && (i < depth); ++i)
167 if (dirComponents[i] != first[i])
168 good = false;
169 if (!good) {
170 fseek (fp, -(strlen (line) + chomped), SEEK_CUR); // equivalent of "pushback"
171 return;
172 }
173 }
174 XMCheckListItem *newitem = new XMCheckListItem (top, dirComponents[dirComponents.size() - 1]);
175 if (!(++lino % 1111)) {
176 status->setText (QString ("Loading filelist - %1% done").arg (lino * 100 / numlines));
177 }
178
179 depth++;
180 XM_load_filelist_sub (fp, dirComponents, newitem, status, numlines);
181 depth--;
182 }
183}
184
185int XM_load_filelist (const char *filelist_fname, QListView *list, QLabel *status, QStringList first = QStringList(), FILE *fp = 0)
186{
187 fp = fopen (filelist_fname, "r");
188 if (!fp) return XMLF_CANTOPEN;
189
190 XMCheckListItem *top = new XMCheckListItem (list, "/");
191
192 status->setText ("Loading filelist - 0% done");
193 XM_load_filelist_sub (fp, QStringList(), top, status, atoi (call_program_and_get_last_line_of_output (const_cast <char*> (QString ("wc -l %1").arg (filelist_fname).ascii()))));
194
195 fclose (fp);
196 return XMLF_OK;
197}
198
199void *XMondoRestore_preparer_thread (void *arg)
200{
201 XMondoRestore *r = static_cast<XMondoRestore*> (arg);
202 int i = 0;
203 g_current_media_number = 1;
204
205 r->fStatusMsg->setText ("Retrieving mondo-restore.cfg from archive...");
206
207 struct s_bkpinfo *bkpinfo = r->bkpinfo;
208 reset_bkpinfo (bkpinfo);
209 switch (r->rMediaType->id (r->rMediaType->selected())) {
210 case 0:
211 bkpinfo->backup_media_type = cdr;
212 break;
213 case 1:
214 bkpinfo->backup_media_type = cdrw;
215 bkpinfo->wipe_media_first = 1;
216 break;
217 case 2:
218 bkpinfo->backup_media_type = cdstream;
219 break;
220 case 3:
221 bkpinfo->backup_media_type = dvd;
222 break;
223 case 4:
224 bkpinfo->backup_media_type = iso;
225 break;
226 case 5:
227 bkpinfo->backup_media_type = nfs;
228 break;
229 case 6:
230 bkpinfo->backup_media_type = tape;
231 break;
232 case 7:
233 bkpinfo->backup_media_type = udev;
234 break;
235 }
236
237 strcpy (bkpinfo->media_device, r->rDevice->text());
238 if (bkpinfo->backup_media_type == nfs) strcpy (bkpinfo->nfs_mount, r->rDevice->text());
239 if (bkpinfo->backup_media_type == nfs) strcpy (bkpinfo->nfs_remote_dir, r->rNFSRemoteDir->text());
240 if (bkpinfo->backup_media_type == iso) strcpy (bkpinfo->isodir, r->rDevice->text());
241 strcpy (bkpinfo->tmpdir, r->tempdir.ascii());
242
243 setup_MR_global_filenames (bkpinfo);
244
245 if (get_cfg_file_from_archive (bkpinfo) != 0) {
246 r->fStatusMsg->setText ("Unable to retrieve mondo-restore.cfg. Please choose another archive source.");
247 r->ok = false;
248 return 0;
249 }
250 read_cfg_file_into_bkpinfo (g_mondo_cfg_file, bkpinfo);
251 if (!does_file_exist (g_mondo_cfg_file)) {
252 r->fStatusMsg->setText ("Unable to retrieve mondo-restore.cfg. Internal error.");
253 r->ok = false;
254 return 0;
255 }
256 if (!does_file_exist (g_filelist_full)) {
257 chdir (bkpinfo->tmpdir);
258 r->fStatusMsg->setText ("Retrieving filelist...");
259 if ((bkpinfo->backup_media_type == tape) || (bkpinfo->backup_media_type == udev) ||
260 (bkpinfo->backup_media_type == cdstream)) {
261 unlink (g_filelist_full);
262 system (QString ("tar -zxf %1 tmp/filelist.full").arg (bkpinfo->media_device).ascii());
263 } else {
264 mount_cdrom (bkpinfo);
265 unlink (g_filelist_full);
266 system ("tar -zxf /mnt/cdrom/images/all.tar.gz tmp/filelist.full");
267 }
268
269 if (!does_file_exist (g_filelist_full)) {
270 r->fStatusMsg->setText ("Filelist could not be retrieved!");
271 r->ok = false;
272 return 0;
273 }
274 }
275 if (!r->rFilter->text().isEmpty() && !r->rFilter->text().isNull()) {
276 r->fStatusMsg->setText (QString ("Filtering filelist through regexp <tt>%1</tt>...").arg (r->rFilter->text()));
277 if (system (QString ("cat %1 | egrep '%2' > %3.FILT").arg (g_filelist_full).arg (r->rFilter->text()).arg (g_filelist_full).ascii()) != 0) {
278 r->fStatusMsg->setText ("Filter failed, using whole filelist");
279 rename (g_filelist_full, QString ("%1.FILT").arg (g_filelist_full).ascii());
280 usleep (500000);
281 }
282 } else {
283 rename (g_filelist_full, QString ("%1.FILT").arg (g_filelist_full).ascii());
284 }
285
286 r->fStatusMsg->setText ("Preparing filelist - 0% done");
287
288 int nlines = atoi (call_program_and_get_last_line_of_output (const_cast<char*> (QString ("wc -l %1.FILT").arg (g_filelist_full).ascii())));
289 int curline = 0;
290 FILE *fin = fopen (QString ("%1.FILT").arg (g_filelist_full).ascii(), "r");
291 FILE *fout = popen (QString ("sort | uniq > %1").arg (g_filelist_full).ascii(), "w");
292
293 if (!(fin && fout)) {
294 r->fStatusMsg->setText ("Can't open filelist");
295 r->ok = false;
296 return 0;
297 }
298
299 char line[4096], tmp[4096];
300 while (fgets (line, 4096, fin)) {
301 if (line[strlen (line) - 1] == '\n')
302 line[strlen (line) - 1] = '\0';
303
304 for (int pos = 0; line[pos] != '\0'; pos++) {
305 if (line[pos] != '/') continue;
306 strcpy (tmp, line);
307 tmp[pos] = '\0';
308 if (strlen (tmp)) {
309 fprintf (fout, "%s\n", tmp);
310 }
311 }
312 fprintf (fout, "%s\n", line);
313 if (!(++curline % 1111)) {
314 r->fStatusMsg->setText (QString ("Preparing filelist - %1% done").arg (curline * 100 / nlines));
315 }
316 }
317
318 fclose (fin);
319 pclose (fout);
320
321 if (XM_load_filelist (g_filelist_full, r->fList, r->fStatusMsg) != XMLF_OK) {
322 r->fStatusMsg->setText ("Error loading filelist");
323 r->ok = false;
324 return 0;
325 }
326 r->fStatusMsg->setText ("Filelist loaded OK");
327
328 r->doneSetup = true;
329 r->fList->setEnabled (true);
330 r->fRestoreDirLabel->setEnabled (true);
331 r->fRestoreDir->setEnabled (true);
332 sleep (1);
333 r->fStatusMsg->setText ("Please select files and directories to be restored.");
334 XMCheckListItem::progressDisplay = r->fStatusMsg;
335 XMCheckListItem::doneSetup = &(r->doneSetup);
336
337 return 0;
338}
339
340XMondoRestore::XMondoRestore (QWidget *parent, QButtonGroup *mediaType, QLineEdit *device, QLineEdit *nfsRemoteDir, QLineEdit *filelistFilter)
341 : QObject (0, 0), rMediaType (mediaType), rDevice (device), rNFSRemoteDir (nfsRemoteDir), rFilter (filelistFilter), ok (true), files (parent), doneSetup (false), th (0)
342{
343 bkpinfo = new s_bkpinfo;
344
345 char tmp[256];
346 strcpy (tmp, "/tmp/xmondo.rstr.XXXXXX");
347 mktemp (tmp);
348 tempdir = tmp;
349 filelistLocation = tempdir + "/filelist.full";
350 cfgLocation = tempdir + "/mondo-restore.cfg";
351 cdMountpoint = "/mnt/cdrom";
352
353 if (!does_file_exist ("/mnt/cdrom")) {
354 if (system ("mkdir -p /mnt/cdrom >/dev/null 2>&1") != 0) {
355 popup_and_OK ("Can't create /mnt/cdrom directory. Aborting restore.");
356 ok = false;
357 return;
358 }
359 }
360
361 QGridLayout *filesGrid;
362 filesGrid = new QGridLayout (files, 3, 2, 5, 5, "filesGrid");
363 fStatusMsg = new QLabel ("", files);
364 fList = new QListView (files);
365 fRestoreDirLabel = new QLabel ("Restore to:", files);
366 fRestoreDir = new QLineEdit (files);
367
368 fList->addColumn ("Files to restore:");
369 fList->setRootIsDecorated (true);
370 fList->setEnabled (false);
371 fRestoreDirLabel->setEnabled (false);
372 fRestoreDir->setEnabled (false);
373 fRestoreDir->setText ("/tmp");
374 filesGrid->addMultiCellWidget (fStatusMsg, 0, 0, 0, 1);
375 filesGrid->addMultiCellWidget (fList, 1, 1, 0, 1);
376 filesGrid->addWidget (fRestoreDirLabel, 2, 0);
377 filesGrid->addWidget (fRestoreDir, 2, 1);
378
379 while (system ("mount | grep -q /mnt/cdrom") == 1) {
380 if (QMessageBox::warning (0, "XMondo", QString ("CD is mounted. Please unmount it and try again."), "&Retry", "&Cancel") == 1 /* Cancel */) {
381 ok = false;
382 return;
383 }
384 }
385
386 pthread_create (&preparer_thread, 0, XMondoRestore_preparer_thread, static_cast <void*> (this));
387 ok = true;
388}
389
390XMondoRestore::~XMondoRestore()
391{
392 chdir ("/");
393 pthread_cancel (preparer_thread);
394 system (QString ("mount | grep xmondo.rstr | cut -d' ' -f3 | xargs umount"));
395 system (QString ("umount %1/mount.bootdisk >/dev/null 2>&1").arg (tempdir).ascii());
396 if ((tempdir != "") && (tempdir != "/") && (tempdir != "/tmp") && (tempdir != "/tmp/")) {
397 system (QString ("rm -rf %1").arg (tempdir).ascii());
398 }
399 system (QString ("umount %1 >/dev/null 2>&1").arg (cdMountpoint).ascii());
400 delete bkpinfo;
401}
402
403int XM_save_filelist (QListViewItem *liTop, const char *fname, QString prefix = QString (""), int numlines = 0, int curline = 0, FILE *fp = 0)
404{
405 static int depth = 0;
406
407 if (!depth) {
408 numlines = atoi (call_program_and_get_last_line_of_output (const_cast<char*> (QString ("wc -l %1").arg (fname).ascii())));
409 fp = fopen (fname, "w");
410 if (!fp) return 1;
411 fprintf (fp, "/\n");
412 if (!liTop) {
413 popup_and_OK ("Internal error. No entries in filelist.");
414 return 255;
415 }
416 }
417
418 XMCheckListItem *top = dynamic_cast<XMCheckListItem*> (liTop);
419 if (!top) return 2;
420
421 for (; top; top = dynamic_cast<XMCheckListItem*> (top->nextSibling())) {
422 if (!top) return 2;
423 if (top->isOn()) {
424 fprintf (fp, "%s/%s\n", prefix.ascii(), top->text().ascii());
425 }
426 if (!(++curline % 1000)) {
427 XMondoProgress->setProgress (curline * 100 / numlines);
428 kapp->processEvents();
429 }
430 if (top->firstChild()) {
431 depth++;
432 XM_save_filelist (top->firstChild(), "", prefix + "/" + top->text(), numlines, curline, fp);
433 depth--;
434 }
435 }
436
437 if (!depth) {
438 fclose (fp);
439 }
440 return 0;
441}
442
443
444void *RestoreThread__run (void *arg);
445
446class RestoreThread
447{
448 friend void *RestoreThread__run (void *arg);
449public:
450 RestoreThread (struct s_bkpinfo *bkpinfo, struct s_node *filelist) : _bkpinfo (bkpinfo), _filelist (filelist),
451 _ret (-1), _aborted (false) {}
452 int returns() {
453 return _ret;
454 }
455 void start() {
456 _running = true;
457 pthread_create (&_thr, 0, RestoreThread__run, this);
458 }
459 void terminate() {
460 _running = false;
461 pthread_cancel (_thr);
462 _thr = 0;
463 }
464 bool running() {
465 return _running;
466 }
467 bool aborted() {
468 return _aborted;
469 }
470protected:
471 static void setStop (void *arg) {
472 RestoreThread *rt = static_cast <RestoreThread*> (arg);
473 if (!rt) return;
474 rt->_running = false;
475 rt->_ret = -1;
476 rt->_aborted = true;
477 }
478 void run() {
479 pthread_cleanup_push (RestoreThread::setStop, this);
480
481 log_to_screen ("Restore started on %s", call_program_and_get_last_line_of_output ("date"));
482 _ret = restore_everything (_bkpinfo, _filelist);
483 log_to_screen ("Restore finished on %s", call_program_and_get_last_line_of_output ("date"));
484 pthread_cleanup_pop (FALSE);
485 _running = false;
486 }
487 struct s_bkpinfo *_bkpinfo;
488 struct s_node *_filelist;
489 int _ret;
490 pthread_t _thr;
491 bool _running;
492 bool _aborted;
493};
494
495void *RestoreThread__run (void *arg)
496{
497 RestoreThread *rt = static_cast <RestoreThread *> (arg);
498 if (!rt && (sizeof(void*) >= 4)) return (void *) 0xDEADBEEF;
499 rt->run();
500}
501
502void XMondoRestore::slotAbortRestore()
503{
504 if (th) th->terminate();
505}
506
507void XM_toggle_everything_on (struct s_node *flist)
508{
509 for (; flist; flist = flist->right) {
510 if (flist->ch == 0) {
511 flist->selected = 1;
512 }
513 if (flist->down) {
514 XM_toggle_everything_on (flist->down);
515 }
516 }
517}
518
519void XMondoRestore::go()
520{
521 if (!doneSetup) {
522 popup_and_OK ("Please wait for the setup to be completed.");
523 ok = false;
524 return;
525 }
526 pthread_cancel (preparer_thread);
527
528
529 disconnect (XMondoCancel, SIGNAL(clicked()), 0, 0);
530 connect (XMondoCancel, SIGNAL(clicked()), this, SLOT(slotAbortRestore()));
531
532 XMondoProgress->show();
533 XMondoProgress->setTotalSteps (100);
534 XMondoProgress->setProgress (0);
535 XMondoProgressWhat->show();
536 XMondoProgressWhat->setText ("Saving your filelist choices.");
537 XMondoProgressWhat2->hide();
538 XMondoProgressWhat3->hide();
539 XMondoTimeTaken->hide();
540 XMondoTimeToGo->hide();
541 XMondoStatus->setText ("Saving filelist");
542 XMondoStatus->show();
543 XMondoLog->setText ("");
544 XMondoLog->show();
545
546 if (XM_save_filelist (fList->firstChild()->firstChild(), g_filelist_full) != 0) {
547 XMondoStatus->setText ("Error saving filelist");
548 ok = false;
549 return;
550 }
551
552 XMondoStatus->setText ("Reloading filelist");
553 /*DEBUG*/ system (QString ("cp %1 /home/oremanj/filelist.tested").arg (g_filelist_full).ascii());
554 s_node *flist = load_filelist (g_filelist_full);
555 if (!flist) {
556 XMondoStatus->setText ("Error loading filelist");
557 ok = false;
558 return;
559 }
560 XM_toggle_everything_on (flist);
561
562 XMondoProgress->hide();
563 XMondoStatus->setText ("Beginning restore");
564 XMondoProgressWhat->hide();
565
566 strcpy (bkpinfo->restore_path, fRestoreDir->text().ascii());
567
568 g_text_mode = 1; // avoid crashing on NEWT functions
569
570 th = new RestoreThread (bkpinfo, flist);
571 th->start();
572 while (th->running()) {
573 usleep (100000);
574 events.send();
575 kapp->processEvents();
576 }
577 free_filelist (flist);
578 if (th->aborted()) {
579 /* do nothing */
580 } else if (th->returns() == 0) {
581 popup_and_OK ("Restore completed with no errors.");
582 } else {
583 popup_and_OK ("Restore completed; however, there were some errors.");
584 }
585 delete th; th = 0;
586 ok = true; // call destructor in caller
587}
Note: See TracBrowser for help on using the repository browser.