From 2bdf88b4afde8c9fbad936be9d02d3ed82d550a5 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 18 Sep 2010 15:04:54 +0200 Subject: [PATCH] Massive bat notifier rewrite + fix seg fault + implement text input dialog --- bacula/src/console/console.c | 2 +- bacula/src/dird/protos.h | 2 +- bacula/src/dird/ua_input.c | 13 +++- bacula/src/dird/ua_tree.c | 2 +- bacula/src/lib/bnet.c | 6 +- bacula/src/lib/bsock.h | 6 +- bacula/src/qt-console/bcomm/dircomm.cpp | 72 ++++++++++++-------- bacula/src/qt-console/bcomm/dircomm.h | 2 +- bacula/src/qt-console/console/console.cpp | 47 +++++++------ bacula/src/qt-console/mainwin.cpp | 15 ++-- bacula/src/qt-console/mainwin.h | 3 + bacula/src/qt-console/restore/prerestore.cpp | 3 +- bacula/src/qt-console/select/select.cpp | 3 +- bacula/src/qt-console/select/textinput.cpp | 16 ++--- 14 files changed, 117 insertions(+), 75 deletions(-) diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 4e0e3f519b..04e51abf81 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -324,7 +324,7 @@ static void read_and_process_input(FILE *input, BSOCK *UA_sock) if (is_bnet_stop(UA_sock)) { break; /* error or term */ } else if (stat == BNET_SIGNAL) { - if (UA_sock->msglen == BNET_PROMPT) { + if (UA_sock->msglen == BNET_SUB_PROMPT) { at_prompt = true; } Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock)); diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 159d6d5352..ae358fd92a 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -210,7 +210,7 @@ void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op); int update_pool_references(JCR *jcr, B_DB *db, POOL *pool); /* ua_input.c */ -int get_cmd(UAContext *ua, const char *prompt); +int get_cmd(UAContext *ua, const char *prompt, bool subprompt=false); bool get_pint(UAContext *ua, const char *prompt); bool get_yesno(UAContext *ua, const char *prompt); bool is_yesno(char *val, int *ret); diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c index 23a629bc5a..2b16f50743 100644 --- a/bacula/src/dird/ua_input.c +++ b/bacula/src/dird/ua_input.c @@ -43,7 +43,11 @@ /* Exported functions */ -int get_cmd(UAContext *ua, const char *prompt) +/* + * If subprompt is set, we send a BNET_SUB_PROMPT signal otherwise + * send a BNET_TEXT_INPUT signal. + */ +int get_cmd(UAContext *ua, const char *prompt, bool subprompt) { BSOCK *sock = ua->UA_sock; int stat; @@ -52,8 +56,13 @@ int get_cmd(UAContext *ua, const char *prompt) if (!sock || ua->batch) { /* No UA or batch mode */ return 0; } + if (!subprompt) { + sock->signal(BNET_TEXT_INPUT); + } sock->fsend("%s", prompt); - sock->signal(BNET_PROMPT); /* request more input */ + if (subprompt) { + sock->signal(BNET_SUB_PROMPT); + } for ( ;; ) { stat = sock->recv(); if (stat == BNET_SIGNAL) { diff --git a/bacula/src/dird/ua_tree.c b/bacula/src/dird/ua_tree.c index fa66a51f55..7d08b56410 100644 --- a/bacula/src/dird/ua_tree.c +++ b/bacula/src/dird/ua_tree.c @@ -130,7 +130,7 @@ bool user_select_files_from_tree(TREE_CTX *tree) ua->send_msg(_("cwd is: %s\n"), cwd); for ( ;; ) { int found, len, i; - if (!get_cmd(ua, "$ ")) { + if (!get_cmd(ua, "$ ", true)) { break; } if (ua->api) user->signal(BNET_CMD_BEGIN); diff --git a/bacula/src/lib/bnet.c b/bacula/src/lib/bnet.c index 43e9a5315c..49fda5b144 100644 --- a/bacula/src/lib/bnet.c +++ b/bacula/src/lib/bnet.c @@ -652,8 +652,10 @@ const char *bnet_sig_to_ascii(BSOCK * bs) return "BNET_HEARTBEAT"; case BNET_HB_RESPONSE: return "BNET_HB_RESPONSE"; - case BNET_PROMPT: - return "BNET_PROMPT"; + case BNET_SUB_PROMPT: + return "BNET_SUB_PROMPT"; + case BNET_TEXT_INPUT: + return "BNET_TEXT_INPUT"; default: sprintf(buf, _("Unknown sig %d"), (int)bs->msglen); return buf; diff --git a/bacula/src/lib/bsock.h b/bacula/src/lib/bsock.h index 430ce4035a..9b9f40c440 100644 --- a/bacula/src/lib/bsock.h +++ b/bacula/src/lib/bsock.h @@ -166,7 +166,7 @@ enum { BNET_POLL = -5, /* Poll request, I'm hanging on a read */ BNET_HEARTBEAT = -6, /* Heartbeat Response requested */ BNET_HB_RESPONSE = -7, /* Only response permited to HB */ - BNET_PROMPT = -8, /* Prompt for subcommand */ + BNET_xxxxxxPROMPT = -8, /* No longer used -- Prompt for subcommand */ BNET_BTIME = -9, /* Send UTC btime */ BNET_BREAK = -10, /* Stop current command -- ctl-c */ BNET_START_SELECT = -11, /* Start of a selection list */ @@ -184,7 +184,9 @@ enum { BNET_RUN_CMD = -23, /* Run command follows */ BNET_YESNO = -24, /* Request yes no response */ BNET_START_RTREE = -25, /* Start restore tree mode */ - BNET_END_RTREE = -26 /* End restore tree mode */ + BNET_END_RTREE = -26, /* End restore tree mode */ + BNET_SUB_PROMPT = -27, /* Indicate we are at a subprompt */ + BNET_TEXT_INPUT = -28 /* Get text input from user */ }; #define BNET_SETBUF_READ 1 /* Arg for bnet_set_buffer_size */ diff --git a/bacula/src/qt-console/bcomm/dircomm.cpp b/bacula/src/qt-console/bcomm/dircomm.cpp index 4e6e978f26..2042cee034 100644 --- a/bacula/src/qt-console/bcomm/dircomm.cpp +++ b/bacula/src/qt-console/bcomm/dircomm.cpp @@ -94,9 +94,7 @@ bool DirComm::connect_dir() goto bail_out; } - if (mainWin->m_connDebug) { - Pmsg2(000, "DirComm %i connecting %s\n", m_conn, m_console->m_dir->name()); - } + if (mainWin->m_connDebug)Pmsg2(000, "DirComm %i connecting %s\n", m_conn, m_console->m_dir->name()); memset(jcr, 0, sizeof(JCR)); mainWin->set_statusf(_("Connecting to Director %s:%d"), m_console->m_dir->address, m_console->m_dir->DIRport); @@ -129,8 +127,9 @@ bool DirComm::connect_dir() if (!cons->tls_ctx) { m_console->display_textf(_("Failed to initialize TLS context for Console \"%s\".\n"), m_console->m_dir->name()); - if (mainWin->m_connDebug) + if (mainWin->m_connDebug) { Pmsg2(000, "DirComm %i BAILING Failed to initialize TLS context for Console %s\n", m_conn, m_console->m_dir->name()); + } goto bail_out; } } @@ -152,8 +151,9 @@ bool DirComm::connect_dir() m_console->display_textf(_("Failed to initialize TLS context for Director \"%s\".\n"), m_console->m_dir->name()); mainWin->set_status("Connection failed"); - if (mainWin->m_connDebug) + if (mainWin->m_connDebug) { Pmsg2(000, "DirComm %i BAILING Failed to initialize TLS context for Director %s\n", m_conn, m_console->m_dir->name()); + } goto bail_out; } } @@ -171,8 +171,9 @@ bool DirComm::connect_dir() NULL, m_console->m_dir->DIRport, 0); if (m_sock == NULL) { mainWin->set_status("Connection failed"); - if (mainWin->m_connDebug) + if (mainWin->m_connDebug) { Pmsg2(000, "DirComm %i BAILING Connection failed %s\n", m_conn, m_console->m_dir->name()); + } goto bail_out; } else { /* Update page selector to green to indicate that Console is connected */ @@ -188,8 +189,9 @@ bool DirComm::connect_dir() if (!authenticate_director(jcr, m_console->m_dir, cons, buf, sizeof(buf))) { m_console->display_text(buf); - if (mainWin->m_connDebug) + if (mainWin->m_connDebug) { Pmsg2(000, "DirComm %i BAILING Connection failed %s\n", m_conn, m_console->m_dir->name()); + } goto bail_out; } @@ -206,8 +208,8 @@ bool DirComm::connect_dir() * Set up input notifier */ m_notifier = new QSocketNotifier(m_sock->m_fd, QSocketNotifier::Read, 0); - QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int))); - m_notifier->setEnabled(false); + QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(notify_read_dir(int))); + m_notifier->setEnabled(true); write(".api 1"); m_api_set = true; @@ -341,19 +343,24 @@ int DirComm::read() mainWin->set_status(_("At main prompt waiting for input ...")); } break; - case BNET_PROMPT: - if (mainWin->m_commDebug) Pmsg2(000, "conn %i PROMPT m_in_select %i\n", m_conn, m_in_select); + case BNET_SUB_PROMPT: + if (mainWin->m_commDebug) Pmsg2(000, "conn %i SUB_PROMPT m_in_select=%d\n", m_conn, m_in_select); m_at_prompt = true; m_at_main_prompt = false; mainWin->set_status(_("At prompt waiting for input ...")); - /***** FIXME *****/ - /* commented out until the prompt communication issue with the director is resolved - * This is where I call a new text input dialog class to prevent the connection issues - * when a text input is requited. - * if (!m_in_select) { - * new textInputDialog(m_console, m_conn); - * } - */ + break; + case BNET_TEXT_INPUT: + if (mainWin->m_commDebug) Pmsg4(000, "conn %i TEXT_INPUT at_prompt=%d m_in_select=%d notify=%d\n", + m_conn, m_at_prompt, m_in_select, is_notify_enabled()); + if (!m_in_select && is_notify_enabled()) { + mainWin->waitExit(); + new textInputDialog(m_console, m_conn); + } else { + if (mainWin->m_commDebug) Pmsg0(000, "!m_in_select && is_notify_enabled\n"); + m_at_prompt = true; + m_at_main_prompt = false; + mainWin->set_status(_("At prompt waiting for input ...")); + } break; case BNET_CMD_FAILED: if (mainWin->m_commDebug) Pmsg1(000, "CMD FAILED\n", m_conn); @@ -413,6 +420,11 @@ int DirComm::read() mainWin->set_status(msg()); break; } + + if (!m_sock) { + stat = BNET_HARDEOF; + return stat; + } if (is_bnet_stop(m_sock)) { /* error or term request */ if (mainWin->m_commDebug) Pmsg1(000, "conn %i BNET STOP\n", m_conn); m_console->stopTimer(); @@ -436,9 +448,12 @@ int DirComm::read() } /* Called by signal when the Director has output for us */ -void DirComm::read_dir(int /* fd */) +void DirComm::notify_read_dir(int /* fd */) { int stat; + if (!mainWin->m_notify) { + return; + } if (mainWin->m_commDebug) Pmsg1(000, "enter read_dir conn %i read_dir\n", m_conn); stat = m_sock->wait_data(0, 5000); if (stat > 0) { @@ -463,24 +478,23 @@ void DirComm::read_dir(int /* fd */) bool DirComm::notify(bool enable) { bool prev_enabled = false; + /* Set global flag */ + mainWin->m_notify = enable; if (m_notifier) { prev_enabled = m_notifier->isEnabled(); - m_notifier->setEnabled(enable); - if (mainWin->m_connDebug) { - Pmsg3(000, "conn=%i notify=%d prev=%d\n", m_conn, enable, prev_enabled); + if (prev_enabled != enable) { + m_notifier->setEnabled(enable); } - } else if (mainWin->m_connDebug) + if (mainWin->m_connDebug) Pmsg3(000, "conn=%i notify=%d prev=%d\n", m_conn, enable, prev_enabled); + } else if (mainWin->m_connDebug) { Pmsg2(000, "m_notifier does not exist: %i %s\n", m_conn, m_console->m_dir->name()); + } return prev_enabled; } bool DirComm::is_notify_enabled() const { - bool enabled = false; - if (m_notifier) { - enabled = m_notifier->isEnabled(); - } - return enabled; + return mainWin->m_notify; } /* diff --git a/bacula/src/qt-console/bcomm/dircomm.h b/bacula/src/qt-console/bcomm/dircomm.h index 8c2b9000b7..fbc0da61e7 100644 --- a/bacula/src/qt-console/bcomm/dircomm.h +++ b/bacula/src/qt-console/bcomm/dircomm.h @@ -72,7 +72,7 @@ public: int write(QString msg); public slots: - void read_dir(int fd); + void notify_read_dir(int fd); private: BSOCK *m_sock; diff --git a/bacula/src/qt-console/console/console.cpp b/bacula/src/qt-console/console/console.cpp index b421fc0029..dcc7d87d63 100644 --- a/bacula/src/qt-console/console/console.cpp +++ b/bacula/src/qt-console/console/console.cpp @@ -97,6 +97,11 @@ void Console::poll_messages() { int conn; + /* Do not poll if notifier off */ + if (!mainWin->m_notify) { + return; + } + /* * Note if we call getDirComm here, we continuously consume * file descriptors. @@ -148,9 +153,7 @@ void Console::populateLists(bool /*forcenew*/) { int conn; if (!getDirComm(conn)) { - if (mainWin->m_connDebug) { - Pmsg0(000, "call newDirComm\n"); - } + if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n"); if (!newDirComm(conn)) { Emsg1(M_ABORT, 0, "Failed to connect to %s for populateLists.\n", m_dir->name()); return; @@ -233,6 +236,7 @@ bool Console::dir_cmd(int conn, const char *cmd, QStringList &results) mainWin->waitEnter(); DirComm *dircomm = m_dircommHash.value(conn); int stat; + bool prev_notify = mainWin->m_notify; if (mainWin->m_connDebug) { QString dbgmsg = QString("dir_cmd conn %1 %2 %3\n").arg(conn).arg(m_dir->name()).arg(cmd); @@ -246,10 +250,12 @@ bool Console::dir_cmd(int conn, const char *cmd, QStringList &results) results << dircomm->msg(); } if (stat > 0 && mainWin->m_displayAll) display_text(dircomm->msg()); - notify(conn, true); + if (prev_notify) { + notify(conn, true); /* turn it back on */ + } discardToPrompt(conn); mainWin->waitExit(); - return true; /* ***FIXME*** return any command error */ + return true; /* ***FIXME*** return any command error */ } /* @@ -287,6 +293,7 @@ bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool d DirComm *dircomm = m_dircommHash.value(conn); int stat; POOL_MEM cmd(PM_MESSAGE); + bool prev_notify = mainWin->m_notify; if (!is_connectedGui()) { return false; @@ -319,7 +326,7 @@ bool Console::sql_cmd(int &conn, const char *query, QStringList &results, bool d } first = false; } - if (donotify) { + if (donotify && prev_notify) { dircomm->notify(true); } discardToPrompt(conn); @@ -402,9 +409,12 @@ bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool do QString scmd; int stat; char *def; + bool prev_notify = mainWin->m_notify; + bool rtn = false; - if (donotify) + if (donotify) { conn = notifyOff(); + } beginNewCommand(conn); DirComm *dircomm = m_dircommHash.value(conn); bool prevWaitState = mainWin->getWaitState(); @@ -471,19 +481,16 @@ bool Console::get_job_defaults(int &conn, struct job_defaults &job_defs, bool do continue; } } - - if (donotify) - notify(conn, true); - if (!prevWaitState) - mainWin->waitExit(); - return true; - + rtn = true; + /* Fall through wanted */ bail_out: - if (donotify) + if (donotify && prev_notify) { notify(conn, true); - if (!prevWaitState) + } + if (!prevWaitState) { mainWin->waitExit(); - return false; + } + return rtn; } @@ -664,6 +671,8 @@ QString Console::returnFromPrompt(int conn) int stat = 0; text = ""; + dircomm->read(); + text += dircomm->msg(); if (mainWin->m_commDebug) Pmsg1(000, "returnFromPrompt %s\n", m_dir->name()); while (!dircomm->m_at_prompt) { if ((stat=dircomm->read()) > 0) { @@ -838,9 +847,7 @@ bool Console::getDirComm(int &conn) if (findDirComm(conn)) { return true; } - if (mainWin->m_connDebug) { - Pmsg0(000, "call newDirComm\n"); - } + if (mainWin->m_connDebug) Pmsg0(000, "call newDirComm\n"); return newDirComm(conn); } diff --git a/bacula/src/qt-console/mainwin.cpp b/bacula/src/qt-console/mainwin.cpp index 15d7565825..7740ae9640 100644 --- a/bacula/src/qt-console/mainwin.cpp +++ b/bacula/src/qt-console/mainwin.cpp @@ -97,6 +97,15 @@ MainWin::MainWin(QWidget *parent) : QMainWindow(parent) foreach(Console *console, m_consoleHash) { console->connect_dir(); } + /* + * Note, the notifier is now a global flag, although each notifier + * can be individually turned on and off at a socket level. Once + * the notifier is turned off, we don't accept anything from anyone + * this prevents unwanted messages from getting into the input + * dialogs such as restore that read from the director and "know" + * what to expect. + */ + m_notify = true; m_currentConsole = (Console*)getFromHash(m_firstItem); QTimer::singleShot(2000, this, SLOT(popLists())); if (m_miscDebug) { @@ -306,9 +315,7 @@ void MainWin::disconnectSignals() */ void MainWin::waitEnter() { - if (m_waitState){ - if (mainWin->m_connDebug) - Pmsg0(000, "Should Never Get Here DANGER DANGER, for now I'll return\n"); + if (m_waitState || m_isClosing) { return; } m_waitState = true; @@ -327,7 +334,6 @@ void MainWin::waitExit() if (!m_waitState || m_isClosing) { return; } - m_waitState = false; if (mainWin->m_connDebug) Pmsg0(000, "Exiting Wait State\n"); if (m_waitTreeItem && (m_waitTreeItem != treeWidget->currentItem())) { treeWidget->setCurrentItem(m_waitTreeItem); @@ -337,6 +343,7 @@ void MainWin::waitExit() connectConsoleSignals(); } app->restoreOverrideCursor(); + m_waitState = false; } void MainWin::connectConsoleSignals() diff --git a/bacula/src/qt-console/mainwin.h b/bacula/src/qt-console/mainwin.h index 6203f03b11..addc501e02 100644 --- a/bacula/src/qt-console/mainwin.h +++ b/bacula/src/qt-console/mainwin.h @@ -105,6 +105,9 @@ public: bool m_openPlot; bool m_openDirStat; + /* Global */ + bool m_notify; /* global flag to turn on/off all notifiers */ + public slots: void input_line(); void about(); diff --git a/bacula/src/qt-console/restore/prerestore.cpp b/bacula/src/qt-console/restore/prerestore.cpp index ad56ba5947..74d8f74f26 100644 --- a/bacula/src/qt-console/restore/prerestore.cpp +++ b/bacula/src/qt-console/restore/prerestore.cpp @@ -27,8 +27,6 @@ */ /* - * Version $Id$ - * * preRestore -> dialog put up to determine the restore type * * Kern Sibbald, February MMVII @@ -140,6 +138,7 @@ void prerestorePage::okButtonPushed() this->hide(); + cmd = QString("restore"); cmd += " fileset=\"" + filesetCombo->currentText() + "\""; cmd += " client=\"" + clientCombo->currentText() + "\""; diff --git a/bacula/src/qt-console/select/select.cpp b/bacula/src/qt-console/select/select.cpp index 4932be39fc..ddc0438a5d 100644 --- a/bacula/src/qt-console/select/select.cpp +++ b/bacula/src/qt-console/select/select.cpp @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2007-2009 Free Software Foundation Europe e.V. + Copyright (C) 2007-2010 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -31,7 +31,6 @@ * * Kern Sibbald, March MMVII * - * $Id$ */ #include "bat.h" diff --git a/bacula/src/qt-console/select/textinput.cpp b/bacula/src/qt-console/select/textinput.cpp index d96ea18540..9c91ba8b52 100644 --- a/bacula/src/qt-console/select/textinput.cpp +++ b/bacula/src/qt-console/select/textinput.cpp @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2007-2009 Free Software Foundation Europe e.V. + Copyright (C) 2007-2010 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -31,7 +31,6 @@ * * Kern Sibbald, March MMVII * - * $Id: select.cpp 8775 2009-04-30 16:57:18Z bartleyd2 $ */ #include "bat.h" @@ -46,9 +45,11 @@ textInputDialog::textInputDialog(Console *console, int conn) QDateTime dt; m_console = console; + m_console->notify(m_conn, false); setupUi(this); setAttribute(Qt::WA_DeleteOnClose); - labelWidget->setText(m_console->returnFromPrompt(m_conn)); + m_console->read(m_conn); /* get title */ + labelWidget->setText(m_console->msg(m_conn)); this->show(); } @@ -56,11 +57,10 @@ void textInputDialog::accept() { this->hide(); m_console->write_dir(m_conn, lineEdit->text().toUtf8().data()); - m_console->displayToPrompt(m_conn); + /* Do not displayToPrompt because there may be another Text Input required */ + this->close(); mainWin->resetFocus(); - m_console->displayToPrompt(m_conn); m_console->notify(m_conn, true); - this->close(); } @@ -68,9 +68,9 @@ void textInputDialog::reject() { this->hide(); mainWin->set_status(tr(" Canceled")); + m_console->write_dir(m_conn, "."); + this->close(); mainWin->resetFocus(); m_console->beginNewCommand(m_conn); m_console->notify(m_conn, true); - this->close(); } - -- 2.39.5