From 4403782e1047647d0afff3e822019b7a5fc002d8 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 13 Aug 2008 14:36:31 +0000 Subject: [PATCH] Fix seg fault in Dir during estimate command with no level value given. This fixes bug #1140. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@7473 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/patches/2.4.2-bat.patch | 416 ++++++++++++++++++++++++ bacula/patches/2.4.2-estimate-cmd.patch | 80 +++++ bacula/projects | 41 +++ bacula/src/dird/ua_cmds.c | 21 +- bacula/src/version.h | 4 +- bacula/technotes-2.5 | 3 + 6 files changed, 560 insertions(+), 5 deletions(-) create mode 100644 bacula/patches/2.4.2-bat.patch create mode 100644 bacula/patches/2.4.2-estimate-cmd.patch diff --git a/bacula/patches/2.4.2-bat.patch b/bacula/patches/2.4.2-bat.patch new file mode 100644 index 0000000000..05ff853bcc --- /dev/null +++ b/bacula/patches/2.4.2-bat.patch @@ -0,0 +1,416 @@ + + This patch should clean up two problems with bat: + 1. Eliminate print error output concerning job plotting + 2. Eliminate the error messages where bat complains about being busy. + It also backports some new trunk code. + Apply it to Bacula version 2.4.2 with: + + cd + patch -p0 <2.4.2-bat.patch + ./configure + make + ... + make install + + +Index: src/qt-console/mainwin.h +=================================================================== +--- src/qt-console/mainwin.h (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/mainwin.h (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -107,9 +107,7 @@ + void runButtonClicked(); + void estimateButtonClicked(); + void browseButtonClicked(); +-#ifdef HAVE_QWT + void jobPlotButtonClicked(); +-#endif + void restoreButtonClicked(); + void undockWindowButton(); + void treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *); +Index: src/qt-console/fileset/fileset.h +=================================================================== +--- src/qt-console/fileset/fileset.h (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/fileset/fileset.h (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -62,6 +62,7 @@ + void createContextMenu(); + QString m_currentlyselected; + bool m_populated; ++ bool m_populating; + bool m_checkcurwidget; + }; + +Index: src/qt-console/fileset/fileset.cpp +=================================================================== +--- src/qt-console/fileset/fileset.cpp (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/fileset/fileset.cpp (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -50,6 +50,7 @@ + + /* mp_treeWidget, FileSet Tree Tree Widget inherited from ui_fileset.h */ + m_populated = false; ++ m_populating = false; + m_checkcurwidget = true; + m_closeable = false; + readSettings(); +@@ -70,6 +71,10 @@ + */ + void FileSet::populateTree() + { ++ if (m_populating) ++ return; ++ m_populating = true; ++ + QTreeWidgetItem *filesetItem, *topItem; + + if (!m_console->preventInUseConnect()) +@@ -102,7 +107,7 @@ + " FROM FileSet" + " WHERE "; + query += " FileSet='" + filesetName + "'"; +- query += " ORDER BY FileSet"; ++ query += " ORDER BY CreateTime DESC LIMIT 1"; + + QStringList results; + if (mainWin->m_sqlDebug) { +@@ -135,7 +140,7 @@ + for (int cnter=0; cnterresizeColumnToContents(cnter); + } +- ++ m_populating = false; + } + + /* +Index: src/qt-console/clients/clients.cpp +=================================================================== +--- src/qt-console/clients/clients.cpp (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/clients/clients.cpp (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -51,6 +51,7 @@ + + /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_client.h */ + m_populated = false; ++ m_populating = false; + m_checkcurwidget = true; + m_closeable = false; + /* add context sensitive menu items specific to this classto the page +@@ -70,6 +71,9 @@ + */ + void Clients::populateTree() + { ++ if (m_populating) ++ return; ++ m_populating = true; + QTreeWidgetItem *clientItem, *topItem; + + if (!m_console->preventInUseConnect()) +@@ -135,6 +139,7 @@ + for(int cnter=0; cnterresizeColumnToContents(cnter); + } ++ m_populating = false; + } + + /* +Index: src/qt-console/clients/clients.h +=================================================================== +--- src/qt-console/clients/clients.h (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/clients/clients.h (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -62,6 +62,7 @@ + void createContextMenu(); + QString m_currentlyselected; + bool m_populated; ++ bool m_populating; + bool m_checkcurwidget; + }; + +Index: src/qt-console/storage/storage.cpp +=================================================================== +--- src/qt-console/storage/storage.cpp (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/storage/storage.cpp (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -52,6 +52,7 @@ + + /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_storage.h */ + m_populated = false; ++ m_populating = false; + m_checkcurwidget = true; + m_closeable = false; + m_currentStorage = ""; +@@ -71,6 +72,9 @@ + */ + void Storage::populateTree() + { ++ if (m_populating) ++ return; ++ m_populating = true; + QTreeWidgetItem *storageItem, *topItem; + + if (!m_console->preventInUseConnect()) +@@ -135,6 +139,7 @@ + for(int cnter=0; cnterresizeColumnToContents(cnter); + } ++ m_populating = false; + } + + /* +Index: src/qt-console/storage/storage.h +=================================================================== +--- src/qt-console/storage/storage.h (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/storage/storage.h (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -66,6 +66,7 @@ + QString m_currentStorage; + int m_currentAutoChanger; + bool m_populated; ++ bool m_populating; + bool m_checkcurwidget; + }; + +Index: src/qt-console/medialist/medialist.h +=================================================================== +--- src/qt-console/medialist/medialist.h (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/medialist/medialist.h (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -66,10 +66,13 @@ + private: + void createContextMenu(); + void setStatusColor(QTreeWidgetItem *, QString &, int &); ++ void writeExpandedSettings(); + QString m_currentVolumeName; + QString m_currentVolumeId; + bool m_populated; ++ bool m_populating; + bool m_checkcurwidget; ++ QTreeWidgetItem *m_topItem; + }; + + #endif /* _MEDIALIST_H_ */ +Index: src/qt-console/medialist/medialist.cpp +=================================================================== +--- src/qt-console/medialist/medialist.cpp (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/medialist/medialist.cpp (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -54,6 +54,7 @@ + + /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_medialist.h */ + m_populated = false; ++ m_populating = false; + m_checkcurwidget = true; + m_closeable = false; + /* add context sensitive menu items specific to this classto the page +@@ -64,6 +65,8 @@ + + MediaList::~MediaList() + { ++ if (m_populated) ++ writeExpandedSettings(); + } + + /* +@@ -72,7 +75,10 @@ + */ + void MediaList::populateTree() + { +- QTreeWidgetItem *mediatreeitem, *pooltreeitem, *topItem; ++ QTreeWidgetItem *mediatreeitem, *pooltreeitem; ++ if (m_populating) ++ return; ++ m_populating = true; + + if (!m_console->preventInUseConnect()) + return; +@@ -85,23 +91,31 @@ + int statusIndex = headerlist.indexOf("Status"); + + m_checkcurwidget = false; ++ if (m_populated) ++ writeExpandedSettings(); + mp_treeWidget->clear(); + m_checkcurwidget = true; + mp_treeWidget->setColumnCount(headerlist.count()); +- topItem = new QTreeWidgetItem(mp_treeWidget); +- topItem->setText(0, "Pools"); +- topItem->setData(0, Qt::UserRole, 0); +- topItem->setExpanded(true); ++ m_topItem = new QTreeWidgetItem(mp_treeWidget); ++ m_topItem->setText(0, "Pools"); ++ m_topItem->setData(0, Qt::UserRole, 0); ++ m_topItem->setExpanded(true); + + mp_treeWidget->setHeaderLabels(headerlist); + ++ QSettings settings(m_console->m_dir->name(), "bat"); ++ settings.beginGroup("MediaListTreeExpanded"); + QString query; + + foreach (QString pool_listItem, m_console->pool_list) { +- pooltreeitem = new QTreeWidgetItem(topItem); ++ pooltreeitem = new QTreeWidgetItem(m_topItem); + pooltreeitem->setText(0, pool_listItem); + pooltreeitem->setData(0, Qt::UserRole, 1); +- pooltreeitem->setExpanded(true); ++ if(settings.contains(pool_listItem)) { ++ pooltreeitem->setExpanded(settings.value(pool_listItem).toBool()); ++ } else { ++ pooltreeitem->setExpanded(true); ++ } + + query = "SELECT Media.VolumeName AS Media, " + " Media.MediaId AS Id, Media.VolStatus AS VolStatus," +@@ -151,10 +165,12 @@ + } /* foreach resultline */ + } /* if results from query */ + } /* foreach pool_listItem */ ++ settings.endGroup(); + /* Resize the columns */ + for(int cnter=0; cnterresizeColumnToContents(cnter); + } ++ m_populating = false; + } + + void MediaList::setStatusColor(QTreeWidgetItem *item, QString &field, int &index) +@@ -362,3 +378,18 @@ + consoleCommand(cmd); + populateTree(); + } ++ ++/* ++ * Write settings to save expanded states of the pools ++ */ ++void MediaList::writeExpandedSettings() ++{ ++ QSettings settings(m_console->m_dir->name(), "bat"); ++ settings.beginGroup("MediaListTreeExpanded"); ++ int childcount = m_topItem->childCount(); ++ for (int cnt=0; cntchild(cnt); ++ settings.setValue(poolitem->text(0), poolitem->isExpanded()); ++ } ++ settings.endGroup(); ++} +Index: src/qt-console/mainwin.cpp +=================================================================== +--- src/qt-console/mainwin.cpp (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/mainwin.cpp (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -441,14 +441,14 @@ + new prerestorePage(); + } + +-#ifdef HAVE_QWT + void MainWin::jobPlotButtonClicked() + { ++#ifdef HAVE_QWT + JobPlotPass pass; + pass.use = false; + new JobPlot(NULL, pass); ++#endif + } +-#endif + + /* + * The user just finished typing a line in the command line edit box +Index: src/qt-console/jobs/jobs.h +=================================================================== +--- src/qt-console/jobs/jobs.h (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/jobs/jobs.h (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -66,6 +66,7 @@ + void createContextMenu(); + QString m_currentlyselected; + bool m_populated; ++ bool m_populating; + bool m_checkcurwidget; + int m_typeIndex; + }; +Index: src/qt-console/jobs/jobs.cpp +=================================================================== +--- src/qt-console/jobs/jobs.cpp (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/jobs/jobs.cpp (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -49,6 +49,7 @@ + + /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_client.h */ + m_populated = false; ++ m_populating = false; + m_checkcurwidget = true; + m_closeable = false; + /* add context sensitive menu items specific to this classto the page +@@ -68,6 +69,9 @@ + */ + void Jobs::populateTree() + { ++ if (m_populating) ++ return; ++ m_populating = true; + QTreeWidgetItem *jobsItem, *topItem; + + if (!m_console->preventInUseConnect()) +Index: src/qt-console/joblist/joblist.cpp +=================================================================== +--- src/qt-console/joblist/joblist.cpp (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/joblist/joblist.cpp (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -60,6 +60,7 @@ + + m_resultCount = 0; + m_populated = false; ++ m_populating = false; + m_closeable = false; + if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) + m_closeable=true; +@@ -106,6 +107,10 @@ + */ + void JobList::populateTable() + { ++ if (m_populating) ++ return; ++ m_populating = true; ++ + QStringList results; + QString resultline; + QBrush blackBrush(Qt::black); +@@ -293,6 +298,7 @@ + tr("The Jobs query returned no results.\n" + "Press OK to continue?"), QMessageBox::Ok ); + } ++ m_populating = false; + } + + void JobList::setStatusColor(QTableWidgetItem *item, QString &field) +@@ -574,9 +580,9 @@ + /* + * Graph this table + */ +-#ifdef HAVE_QWT + void JobList::graphTable() + { ++#ifdef HAVE_QWT + JobPlotPass pass; + pass.recordLimitCheck = limitCheckBox->checkState(); + pass.daysLimitCheck = daysCheckBox->checkState(); +@@ -592,8 +598,8 @@ + pass.use = true; + QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this); + new JobPlot(pageSelectorTreeWidgetItem, pass); ++#endif + } +-#endif + + /* + * Save user settings associated with this page +Index: src/qt-console/joblist/joblist.h +=================================================================== +--- src/qt-console/joblist/joblist.h (.../tags/Release-2.4.2/bacula) (revision 7468) ++++ src/qt-console/joblist/joblist.h (.../branches/Branch-2.4/bacula) (revision 7468) +@@ -67,9 +67,7 @@ + void preRestoreFromTime(); + void showLogForJob(); + void consoleCancelJob(); +-#ifdef HAVE_QWT + void graphTable(); +-#endif + + private: + void createConnections(); +@@ -85,6 +83,7 @@ + QString m_filesetName; + QString m_currentJob; + bool m_populated; ++ bool m_populating; + bool m_checkCurrentWidget; + int m_purgedIndex; + int m_typeIndex; diff --git a/bacula/patches/2.4.2-estimate-cmd.patch b/bacula/patches/2.4.2-estimate-cmd.patch new file mode 100644 index 0000000000..ff98b5447e --- /dev/null +++ b/bacula/patches/2.4.2-estimate-cmd.patch @@ -0,0 +1,80 @@ + + This patch fixes the seg faults that occur in the Director if an incorrect + estimate command is given -- in particular a level specification without + the value. This fixes bug #1140 + Apply this patch to Bacula 2.4.2 (and possibly earlier versions) with: + + cd + patch -p0 <2.4.2-estimate-cmd.patch + ./configure + make + ... + make install + + + +Index: src/dird/ua_cmds.c +=================================================================== +--- src/dird/ua_cmds.c (revision 7469) ++++ src/dird/ua_cmds.c (working copy) +@@ -1079,17 +1079,31 @@ + strcasecmp(ua->argk[i], NT_("fd")) == 0) { + if (ua->argv[i]) { + client = GetClientResWithName(ua->argv[i]); ++ if (!client) { ++ ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]); ++ return 1; ++ } + continue; ++ } else { ++ ua->error_msg(_("Client name missing.\n")); ++ return 1; + } + } + if (strcasecmp(ua->argk[i], NT_("job")) == 0) { + if (ua->argv[i]) { + job = GetJobResWithName(ua->argv[i]); +- if (job && !acl_access_ok(ua, Job_ACL, job->name())) { ++ if (!job) { ++ ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]); ++ return 1; ++ } ++ if (!acl_access_ok(ua, Job_ACL, job->name())) { + ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name()); + return 1; + } + continue; ++ } else { ++ ua->error_msg(_("Job name missing.\n")); ++ return 1; + } + } + if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) { +@@ -1100,15 +1114,25 @@ + return 1; + } + continue; ++ } else { ++ ua->error_msg(_("Fileset name missing.\n")); ++ return 1; + } ++ + } + if (strcasecmp(ua->argk[i], NT_("listing")) == 0) { + listing = 1; + continue; + } + if (strcasecmp(ua->argk[i], NT_("level")) == 0) { +- if (!get_level_from_name(ua->jcr, ua->argv[i])) { +- ua->error_msg(_("Level %s not valid.\n"), ua->argv[i]); ++ if (ua->argv[i]) { ++ if (!get_level_from_name(ua->jcr, ua->argv[i])) { ++ ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]); ++ } ++ continue; ++ } else { ++ ua->error_msg(_("Level value missing.\n")); ++ return 1; + } + continue; + } diff --git a/bacula/projects b/bacula/projects index e5b7e2c35e..ce1218f04a 100644 --- a/bacula/projects +++ b/bacula/projects @@ -1324,6 +1324,47 @@ Item 1: Backup and Restore of Windows Encrypted Files through raw encryption fun verify a certain volume. All of these would naturaly apply only for Jobs whose file information are still in the catalog. +Item X: Add EFS support on Windows + Origin: Alex Ehrlich (Alex.Ehrlich-at-mail.ee) + Date: 05 August 2008 + Status: + + What: For each file backed up or restored by FD on Windows, check if + the file is encrypted; if so then use OpenEncryptedFileRaw, + ReadEncryptedFileRaw, WriteEncryptedFileRaw, + CloseEncryptedFileRaw instead of BackupRead and BackupWrite + API calls. + + Why: Many laptop users utilize the EFS functionality today; so do. + some non-laptop ones, too. + Currently files encrypted by means of EFS cannot be backed up. + It means a Windows boutique cannot rely on Bacula as its + backup solution, at least when using Windows 2K, XPP, + "better" Vista etc on workstations, unless EFS is + forbidden by policies. + The current situation might result into "false sense of + security" among the end-users. + + Notes: Using xxxEncryptedFileRaw API would allow to backup and + restore EFS-encrypted files without decrypting their data. + Note that such files cannot be restored "portably" (at least, + easily) but they would be restoreable to a different (or + reinstalled) Win32 machine; the restore would require setup + of a EFS recovery agent in advance, of course, and this shall + be clearly reflected in the documentation, but this is the + normal Windows SysAdmin's business. + When "portable" backup is requested the EFS-encrypted files + shall be clearly reported as errors. + See MSDN on the "Backup and Restore of Encrypted Files" topic: + http://msdn.microsoft.com/en-us/library/aa363783.aspx + Maybe the EFS support requires a new flag in the database for + each file, too? + Unfortunately, the implementation is not as straightforward as + 1-to-1 replacement of BackupRead with ReadEncryptedFileRaw, + requiring some FD code rewrite to work with + encrypted-file-related callback functions. + + encrypted-file-related callback functions. ========== Already implemented ================================ Item n: make changing "spooldata=yes|no" possible for diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 208d9095e8..ac4b89fc77 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -1084,6 +1084,9 @@ static int estimate_cmd(UAContext *ua, const char *cmd) return 1; } continue; + } else { + ua->error_msg(_("Client name missing.\n")); + return 1; } } if (strcasecmp(ua->argk[i], NT_("job")) == 0) { @@ -1098,7 +1101,11 @@ static int estimate_cmd(UAContext *ua, const char *cmd) return 1; } continue; + } else { + ua->error_msg(_("Job name missing.\n")); + return 1; } + } if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) { if (ua->argv[i]) { @@ -1112,6 +1119,9 @@ static int estimate_cmd(UAContext *ua, const char *cmd) return 1; } continue; + } else { + ua->error_msg(_("Fileset name missing.\n")); + return 1; } } if (strcasecmp(ua->argk[i], NT_("listing")) == 0) { @@ -1119,10 +1129,15 @@ static int estimate_cmd(UAContext *ua, const char *cmd) continue; } if (strcasecmp(ua->argk[i], NT_("level")) == 0) { - if (!get_level_from_name(ua->jcr, ua->argv[i])) { - ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]); + if (ua->argv[i]) { + if (!get_level_from_name(ua->jcr, ua->argv[i])) { + ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]); + } + continue; + } else { + ua->error_msg(_("Level value missing.\n")); + return 1; } - continue; } } if (!job && !(client && fileset)) { diff --git a/bacula/src/version.h b/bacula/src/version.h index e65f12ae87..24c02cccde 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "2.5.3" -#define BDATE "08 Aug 2008" -#define LSMDATE "08Aug08" +#define BDATE "12 Aug 2008" +#define LSMDATE "12Aug08" #define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n" #define BYEAR "2008" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.5 b/bacula/technotes-2.5 index 6c355d22e5..a7453becf0 100644 --- a/bacula/technotes-2.5 +++ b/bacula/technotes-2.5 @@ -32,6 +32,9 @@ separator in console (!$%&'()*+,-/:;<>?[]^`{|}~) General: +12Aug08 +kes Fix seg fault in Dir during estimate command with no level value + given. This fixes bug #1140. 08Aug08 kes Add message to migration job when the target job is already migrated. This closes bug #1129. -- 2.39.5