source: branches/2.04_berlios/mondo/mondo/xmondo/xmondorestore.cpp @ 2708

Last change on this file since 2708 was 2708, checked in by bruno, 9 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
Line 
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
7    cvsid                : $Id: xmondorestore.cpp 2708 2011-01-27 18:31:44Z bruno $
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.