diff --git a/cddl/sbin/zfsd/case_file.cc b/cddl/sbin/zfsd/case_file.cc index dbba13ab9fc5..218c9d14979e 100644 --- a/cddl/sbin/zfsd/case_file.cc +++ b/cddl/sbin/zfsd/case_file.cc @@ -59,11 +59,9 @@ #include #include -#include #include #include #include -#include #include "callout.h" #include "vdev_iterator.h" @@ -89,7 +87,6 @@ using DevCtl::EventBuffer; using DevCtl::EventFactory; using DevCtl::EventList; using DevCtl::Guid; -using DevCtl::IstreamReader; using DevCtl::ParseException; /*-------------------------- File-scoped classes ----------------------------*/ @@ -840,26 +837,28 @@ CaseFile::Serialize() close(fd); } +/* + * XXX: This method assumes that events may not contain embedded newlines. If + * ever events can contain embedded newlines, then CaseFile must switch + * serialization formats + */ void CaseFile::DeSerialize(ifstream &caseStream) { - stringstream fakeDevdSocket(stringstream::in|stringstream::out); - IstreamReader caseReader(&fakeDevdSocket); - EventBuffer eventBuffer(caseReader); string evString; + const EventFactory &factory(ZfsDaemon::Get().GetFactory()); caseStream >> std::noskipws >> std::ws; - while (!caseStream.eof()) { + while (caseStream.good()) { /* * Outline: * read the beginning of a line and check it for * "tentative". If found, discard "tentative". - * Shove into fakeDevdSocket. - * call ExtractEvent + * Create a new event * continue */ EventList* destEvents; - string tentFlag("tentative "); + const string tentFlag("tentative "); string line; std::stringbuf lineBuf; @@ -867,20 +866,16 @@ CaseFile::DeSerialize(ifstream &caseStream) caseStream.ignore(); /*discard the newline character*/ line = lineBuf.str(); if (line.compare(0, tentFlag.size(), tentFlag) == 0) { + /* Discard "tentative" */ line.erase(0, tentFlag.size()); destEvents = &m_tentativeEvents; } else { destEvents = &m_events; } - fakeDevdSocket << line; - fakeDevdSocket << '\n'; - const EventFactory &factory(ZfsDaemon::Get().GetFactory()); - while (eventBuffer.ExtractEvent(evString)) { - Event *event(Event::CreateEvent(factory, evString)); - if (event != NULL) { - destEvents->push_back(event); - RegisterCallout(*event); - } + Event *event(Event::CreateEvent(factory, line)); + if (event != NULL) { + destEvents->push_back(event); + RegisterCallout(*event); } } } @@ -1032,7 +1027,7 @@ CaseFile::Replace(const char* vdev_type, const char* path, bool isspare) { Vdev vd(zhp, CaseVdev(zhp)); Vdev replaced(BeingReplacedBy(zhp)); - if (!vd.IsSpare() && !replaced.DoesNotExist()) { + if (isspare && !vd.IsSpare() && !replaced.DoesNotExist()) { /* If we are already being replaced by a working spare, pass. */ if (replaced.IsResilvering() || replaced.State() == VDEV_STATE_HEALTHY) { @@ -1044,12 +1039,10 @@ CaseFile::Replace(const char* vdev_type, const char* path, bool isspare) { * If we have already been replaced by a spare, but that spare * is broken, we must spare the spare, not the original device. */ - if (isspare) { - oldstr = replaced.GUIDString(); - syslog(LOG_INFO, "CaseFile::Replace(%s->%s): sparing " - "broken spare %s instead", VdevGUIDString().c_str(), - path, oldstr.c_str()); - } + oldstr = replaced.GUIDString(); + syslog(LOG_INFO, "CaseFile::Replace(%s->%s): sparing " + "broken spare %s instead", VdevGUIDString().c_str(), + path, oldstr.c_str()); } /* diff --git a/cddl/sbin/zfsd/tests/Makefile b/cddl/sbin/zfsd/tests/Makefile index 3a1aa2baf5e3..4d8c0b565b83 100644 --- a/cddl/sbin/zfsd/tests/Makefile +++ b/cddl/sbin/zfsd/tests/Makefile @@ -7,8 +7,6 @@ SRCDIR=${.CURDIR}/../../../.. PROG_CXX= zfsd_unittest SRCS:= ${SRCS:Nzfsd_main.cc} SRCS+= libmocks.c zfsd_unittest.cc -CLEANFILES+= *.gcno *.gcda *.info -CLEANDIRS+= lcov-report # Use #include in test programs. INCFLAGS+= -I ${.CURDIR}/../.. @@ -26,9 +24,6 @@ LIBRARY_PATH= .endif ZFSD_UNITTEST= env LD_LIBRARY_PATH=${LIBRARY_PATH} ./zfsd_unittest -# Extra tools -LCOV= lcov - # Googletest options LOCALBASE?= /usr/local INCFLAGS+= -I ${LOCALBASE}/include -D_THREAD_SAFE -pthread @@ -42,42 +37,12 @@ LDADD+= ${LOCALBASE}/lib/libgmock.a ${LOCALBASE}/lib/libgmock_main.a # https://groups.google.com/forum/#!msg/googletestframework/h8ixEPCFm0o/amwfu4xGJb0J CFLAGS+= -DGTEST_HAS_PTHREAD -# GCOV options -CFLAGS+= -fprofile-arcs -ftest-coverage -LDADD+= -lgcov - -all: tests - # Install the tests TESTSBASE?= /usr/tests -TESTSDIR= ${TESTSBASE}/zfsd +TESTSDIR= ${TESTSBASE}/cddl/sbin/zfsd # TODO: Convert from an ATF SH test to a Kyua plain test # Long term TODO: Convert to a Kyua googletest test -TESTS_SH+= zfsd_test +ATF_TESTS_SH+= zfsd_test BINDIR= ${TESTSDIR} -# Install the gcov annotation files too -FILESDIR= ${TESTSDIR} -GCNOS= ${SRCS:C/.c+$/.gcno/} -${GCNOS}: ${SRCS:C/.c+$/.o/} -FILES= ${GCNOS} - - -# Run the tests and produce the coverage report -EXCLUDE_PATTERNS='/usr/include/*' '${LOCALBASE}/include/*' -EXCLUDE_PATTERNS+= '*/cddl/compat/opensolaris/include/*' -EXCLUDE_PATTERNS+= '*/tools/regression/zfsd/*' -.PHONY: tests -tests: zfsd_unittest - ${ZFSD_UNITTEST} --gmock_verbose=error - -.PHONY: lcov -lcov: zfsd_unittest - ${LCOV} -z -d . -f && \ - ${ZFSD_UNITTEST} --gmock_verbose=error - ${LCOV} -f -d . -c -o default.info && \ - ${LCOV} -r default.info $(EXCLUDE_PATTERNS) -o trimmed.info && \ - mkdir -p lcov-report && \ - genhtml -o lcov-report trimmed.info - -.include +.include diff --git a/cddl/sbin/zfsd/tests/zfsd_test.sh b/cddl/sbin/zfsd/tests/zfsd_test.sh index d549eebb2656..11690697339c 100644 --- a/cddl/sbin/zfsd/tests/zfsd_test.sh +++ b/cddl/sbin/zfsd/tests/zfsd_test.sh @@ -43,7 +43,26 @@ zfsd_unittest_head() zfsd_unittest_body() { - atf_check -s exit:0 -o ignore -e ignore $(atf_get_srcdir)/zfsd_unittest + TESTPROG=$(atf_get_srcdir)/zfsd_unittest + if atf_config_has coverage_dir; then + # If coverage_dir is defined, then we want to save the .gcda + # and .gcno files for future analysis. Put them in a directory + # tree that resembles /usr/src, but is anchored at + # coverage_dir. + export GCOV_PREFIX=`atf_config_get coverage_dir` + # Examine zfsd_unittest to calculate the GCOV_PREFIX_STRIP + # The outer echo command is needed to strip off whitespace + # printed by wc + OLDGCDADIR=`strings $TESTPROG | grep 'zfsd.gcda'` + export GCOV_PREFIX_STRIP=$( echo $( echo $OLDGCDADIR | \ + sed -e 's:/cddl/sbin/zfsd.*::' -e 's:/: :g' | \ + wc -w ) ) + NEWGCDADIR=$GCOV_PREFIX/`dirname $OLDGCDADIR | \ + sed -e 's:.*\(cddl/sbin/zfsd\):\1:'` + mkdir -p $NEWGCDADIR + cp $(atf_get_srcdir)/*.gcno $NEWGCDADIR + fi + atf_check -s exit:0 -o ignore -e ignore $TESTPROG } atf_init_test_cases() diff --git a/cddl/sbin/zfsd/tests/zfsd_unittest.cc b/cddl/sbin/zfsd/tests/zfsd_unittest.cc index ac425d171240..6c9a4f3094bd 100644 --- a/cddl/sbin/zfsd/tests/zfsd_unittest.cc +++ b/cddl/sbin/zfsd/tests/zfsd_unittest.cc @@ -47,11 +47,9 @@ #include #include -#include #include #include #include -#include #include #include @@ -365,17 +363,12 @@ TEST_F(VdevTest, AvailSpareState) { /* Test the Vdev::IsSpare method */ TEST_F(VdevTest, IsSpare) { - Vdev* vdev; - - vdev = new Vdev(m_poolConfig, m_vdevConfig); - EXPECT_EQ(false, vdev->IsSpare()); - delete vdev; - + Vdev notSpare(m_poolConfig, m_vdevConfig); + EXPECT_EQ(false, notSpare.IsSpare()); ASSERT_EQ(0, nvlist_add_uint64(m_vdevConfig, ZPOOL_CONFIG_IS_SPARE, 1)); - vdev = new Vdev(m_poolConfig, m_vdevConfig); - EXPECT_EQ(true, vdev->IsSpare()); - delete vdev; + Vdev isSpare(m_poolConfig, m_vdevConfig); + EXPECT_EQ(true, isSpare.IsSpare()); } /* diff --git a/cddl/sbin/zfsd/vdev.cc b/cddl/sbin/zfsd/vdev.cc index cbf668966c41..dbba3172d83a 100644 --- a/cddl/sbin/zfsd/vdev.cc +++ b/cddl/sbin/zfsd/vdev.cc @@ -50,7 +50,6 @@ #include #include -#include #include #include #include diff --git a/cddl/sbin/zfsd/zfsd.cc b/cddl/sbin/zfsd/zfsd.cc index b16ecfb46c8e..a4eda63b1ae8 100644 --- a/cddl/sbin/zfsd/zfsd.cc +++ b/cddl/sbin/zfsd/zfsd.cc @@ -59,11 +59,9 @@ #include #include -#include #include #include #include -#include #include "callout.h" #include "vdev_iterator.h" @@ -82,11 +80,8 @@ __FBSDID("$FreeBSD$"); /*============================ Namespace Control =============================*/ using DevCtl::Event; -using DevCtl::EventBuffer; using DevCtl::EventFactory; using DevCtl::EventList; -using DevCtl::Guid; -using DevCtl::NVPairMap; /*================================ Global Data ===============================*/ int g_debug = 0; @@ -103,8 +98,8 @@ int ZfsDaemon::s_signalPipeFD[2]; bool ZfsDaemon::s_systemRescanRequested(false); EventFactory::Record ZfsDaemon::s_registryEntries[] = { - { Event::NOTIFY, "DEVFS", &DevfsEvent::DevfsEventBuilder }, - { Event::NOTIFY, "ZFS", &ZfsEvent::ZfsEventBuilder } + { Event::NOTIFY, "DEVFS", &DevfsEvent::Builder }, + { Event::NOTIFY, "ZFS", &ZfsEvent::Builder } }; //- ZfsDaemon Static Public Methods -------------------------------------------- diff --git a/cddl/sbin/zfsd/zfsd.h b/cddl/sbin/zfsd/zfsd.h index 94bbd83108e9..c9135b3f7e73 100644 --- a/cddl/sbin/zfsd/zfsd.h +++ b/cddl/sbin/zfsd/zfsd.h @@ -52,7 +52,6 @@ * #include * #include * #include - * #include * * #include "vdev_iterator.h" */ diff --git a/cddl/sbin/zfsd/zfsd_event.cc b/cddl/sbin/zfsd/zfsd_event.cc index 5be4ee678cda..ad53383c69a8 100644 --- a/cddl/sbin/zfsd/zfsd_event.cc +++ b/cddl/sbin/zfsd/zfsd_event.cc @@ -51,7 +51,6 @@ #include #include #include -#include #include "callout.h" #include "vdev_iterator.h" @@ -75,9 +74,9 @@ using std::stringstream; //- DevfsEvent Static Public Methods ------------------------------------------- Event * -DevfsEvent::DevfsEventBuilder(Event::Type type, - NVPairMap &nvPairs, - const string &eventString) +DevfsEvent::Builder(Event::Type type, + NVPairMap &nvPairs, + const string &eventString) { return (new DevfsEvent(type, nvPairs, eventString)); } @@ -230,8 +229,8 @@ DevfsEvent::DevfsEvent(const DevfsEvent &src) /*--------------------------------- ZfsEvent ---------------------------------*/ //- ZfsEvent Static Public Methods --------------------------------------------- DevCtl::Event * -ZfsEvent::ZfsEventBuilder(Event::Type type, NVPairMap &nvpairs, - const string &eventString) +ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs, + const string &eventString) { return (new ZfsEvent(type, nvpairs, eventString)); } diff --git a/cddl/sbin/zfsd/zfsd_event.h b/cddl/sbin/zfsd/zfsd_event.h index f2f7967ae7a8..d4d28ee6b465 100644 --- a/cddl/sbin/zfsd/zfsd_event.h +++ b/cddl/sbin/zfsd/zfsd_event.h @@ -66,7 +66,7 @@ class DevfsEvent : public DevCtl::DevfsEvent { public: /** Specialized DevCtlEvent object factory for Devfs events. */ - static BuildMethod DevfsEventBuilder; + static BuildMethod Builder; virtual DevCtl::Event *DeepCopy() const; @@ -122,7 +122,7 @@ class ZfsEvent : public DevCtl::ZfsEvent { public: /** Specialized DevCtlEvent object factory for ZFS events. */ - static BuildMethod ZfsEventBuilder; + static BuildMethod Builder; virtual DevCtl::Event *DeepCopy() const; diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 083054eb2748..ae41c5143102 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -54,6 +54,8 @@ lib .. sbin + zfsd + .. .. usr.bin .. diff --git a/lib/libdevctl/Makefile b/lib/libdevctl/Makefile index 250538f1ae22..9dace3327361 100644 --- a/lib/libdevctl/Makefile +++ b/lib/libdevctl/Makefile @@ -3,18 +3,14 @@ LIB= devctl INCS= consumer.h \ event.h \ - event_buffer.h \ event_factory.h \ exception.h \ - guid.h \ - reader.h + guid.h SRCS= consumer.cc \ event.cc \ - event_buffer.cc \ event_factory.cc \ exception.cc \ - guid.cc \ - reader.cc + guid.cc INCSDIR= ${INCLUDEDIR}/devctl diff --git a/lib/libdevctl/consumer.cc b/lib/libdevctl/consumer.cc index fe014b328525..d325206ea317 100644 --- a/lib/libdevctl/consumer.cc +++ b/lib/libdevctl/consumer.cc @@ -37,24 +37,24 @@ #include #include #include -#include #include #include #include +#include #include #include +#include +#include #include #include #include #include "guid.h" #include "event.h" -#include "event_buffer.h" #include "event_factory.h" #include "exception.h" -#include "reader.h" #include "consumer.h" @@ -71,15 +71,13 @@ namespace DevCtl /*============================= Class Definitions ============================*/ /*----------------------------- DevCtl::Consumer -----------------------------*/ //- Consumer Static Private Data ----------------------------------------------- -const char Consumer::s_devdSockPath[] = "/var/run/devd.pipe"; +const char Consumer::s_devdSockPath[] = "/var/run/devd.seqpacket.pipe"; //- Consumer Public Methods ---------------------------------------------------- Consumer::Consumer(Event::BuildMethod *defBuilder, EventFactory::Record *regEntries, size_t numEntries) : m_devdSockFD(-1), - m_reader(NULL), - m_eventBuffer(NULL), m_eventFactory(defBuilder), m_replayingEvents(false) { @@ -89,8 +87,6 @@ Consumer::Consumer(Event::BuildMethod *defBuilder, Consumer::~Consumer() { DisconnectFromDevd(); - delete m_reader; - m_reader = NULL; } bool @@ -112,9 +108,11 @@ Consumer::ConnectToDevd() strlcpy(devdAddr.sun_path, s_devdSockPath, sizeof(devdAddr.sun_path)); sLen = SUN_LEN(&devdAddr); - m_devdSockFD = socket(AF_UNIX, SOCK_STREAM, 0); + m_devdSockFD = socket(AF_UNIX, SOCK_SEQPACKET, 0); if (m_devdSockFD == -1) err(1, "Unable to create socket"); + if (fcntl(m_devdSockFD, F_SETFL, O_NONBLOCK) < 0) + err(1, "fcntl"); result = connect(m_devdSockFD, reinterpret_cast(&devdAddr), sLen); @@ -124,9 +122,6 @@ Consumer::ConnectToDevd() return (false); } - /* Connect the stream to the file descriptor */ - m_reader = new FDReader(m_devdSockFD); - m_eventBuffer = new EventBuffer(*m_reader); syslog(LOG_INFO, "Connection to devd successful"); return (true); } @@ -137,14 +132,26 @@ Consumer::DisconnectFromDevd() if (m_devdSockFD != -1) syslog(LOG_INFO, "Disconnecting from devd."); - delete m_eventBuffer; - m_eventBuffer = NULL; - delete m_reader; - m_reader = NULL; close(m_devdSockFD); m_devdSockFD = -1; } +std::string +Consumer::ReadEvent() +{ + char buf[MAX_EVENT_SIZE + 1]; + ssize_t len; + + len = ::recv(m_devdSockFD, buf, MAX_EVENT_SIZE, MSG_WAITALL); + if (len == -1) + return (std::string("")); + else { + /* NULL-terminate the result */ + buf[len] = '\0'; + return (std::string(buf)); + } +} + void Consumer::ReplayUnconsumedEvents(bool discardUnconsumed) { @@ -178,20 +185,20 @@ Consumer::SaveEvent(const Event &event) } Event * -Consumer::NextEvent(EventBuffer *eventBuffer) +Consumer::NextEvent() { if (!Connected()) return(NULL); - if (eventBuffer == NULL) - eventBuffer = m_eventBuffer; - Event *event(NULL); try { string evString; - if (eventBuffer->ExtractEvent(evString)) + evString = ReadEvent(); + if (! evString.empty()) { + Event::TimestampEventString(evString); event = Event::CreateEvent(m_eventFactory, evString); + } } catch (const Exception &exp) { exp.Log(); DisconnectFromDevd(); @@ -201,10 +208,10 @@ Consumer::NextEvent(EventBuffer *eventBuffer) /* Capture and process buffered events. */ void -Consumer::ProcessEvents(EventBuffer *eventBuffer) +Consumer::ProcessEvents() { Event *event; - while ((event = NextEvent(eventBuffer)) != NULL) { + while ((event = NextEvent()) != NULL) { if (event->Process()) SaveEvent(*event); delete event; @@ -214,10 +221,11 @@ Consumer::ProcessEvents(EventBuffer *eventBuffer) void Consumer::FlushEvents() { - char discardBuf[256]; + std::string s; - while (m_reader->in_avail() > 0) - m_reader->read(discardBuf, sizeof(discardBuf)); + do + s = ReadEvent(); + while (! s.empty()) ; } bool diff --git a/lib/libdevctl/consumer.h b/lib/libdevctl/consumer.h index f8242425a3ac..335bdaadf8ef 100644 --- a/lib/libdevctl/consumer.h +++ b/lib/libdevctl/consumer.h @@ -81,14 +81,13 @@ public: */ void ReplayUnconsumedEvents(bool discardUnconsumed); - /** Return an event, if available, from the provided EventBuffer. */ - Event *NextEvent(EventBuffer *eventBuffer = NULL); + /** Return an event, if one is available. */ + Event *NextEvent(); /** - * Extract events from the provided eventBuffer and invoke - * each event's Process method. + * Extract events and invoke each event's Process method. */ - void ProcessEvents(EventBuffer *eventBuffer = NULL); + void ProcessEvents(); /** Discard all data pending in m_devdSockFD. */ void FlushEvents(); @@ -116,6 +115,22 @@ public: EventFactory GetFactory(); protected: + /** + * \brief Reads the most recent record + * + * On error, "" is returned, and errno will be set by the OS + * + * \returns A string containing the record + */ + std::string ReadEvent(); + + enum { + /* + * The maximum event size supported by libdevctl. + */ + MAX_EVENT_SIZE = 8192, + }; + static const char s_devdSockPath[]; /** diff --git a/lib/libdevctl/event.cc b/lib/libdevctl/event.cc index 38a0c2c1e198..07f67210313f 100644 --- a/lib/libdevctl/event.cc +++ b/lib/libdevctl/event.cc @@ -40,12 +40,18 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include +#include +#include #include #include #include @@ -86,8 +92,8 @@ Event::EventTypeRecord Event::s_typeTable[] = //- Event Static Public Methods ------------------------------------------------ Event * -Event::EventBuilder(Event::Type type, NVPairMap &nvPairs, - const string &eventString) +Event::Builder(Event::Type type, NVPairMap &nvPairs, + const string &eventString) { return (new Event(type, nvPairs, eventString)); } @@ -325,11 +331,35 @@ Event::ParseEventString(Event::Type type, } } +void +Event::TimestampEventString(std::string &eventString) +{ + if (eventString.size() > 0) { + /* + * Add a timestamp as the final field of the event if it is + * not already present. + */ + if (eventString.find("timestamp=") == string::npos) { + const size_t bufsize = 32; // Long enough for a 64-bit int + timeval now; + struct tm* time_s; + char timebuf[bufsize]; + + size_t eventEnd(eventString.find_last_not_of('\n') + 1); + if (gettimeofday(&now, NULL) != 0) + err(1, "gettimeofday"); + time_s = gmtime(&now.tv_sec); + strftime(timebuf, bufsize, " timestamp=%s", time_s); + eventString.insert(eventEnd, timebuf); + } + } +} + /*-------------------------------- DevfsEvent --------------------------------*/ //- DevfsEvent Static Public Methods ------------------------------------------- Event * -DevfsEvent::DevfsEventBuilder(Event::Type type, NVPairMap &nvPairs, - const string &eventString) +DevfsEvent::Builder(Event::Type type, NVPairMap &nvPairs, + const string &eventString) { return (new DevfsEvent(type, nvPairs, eventString)); } @@ -495,8 +525,8 @@ DevfsEvent::DevfsEvent(const DevfsEvent &src) /*--------------------------------- ZfsEvent ---------------------------------*/ //- ZfsEvent Static Public Methods --------------------------------------------- Event * -ZfsEvent::ZfsEventBuilder(Event::Type type, NVPairMap &nvpairs, - const string &eventString) +ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs, + const string &eventString) { return (new ZfsEvent(type, nvpairs, eventString)); } diff --git a/lib/libdevctl/event.h b/lib/libdevctl/event.h index 9f13f91db335..eac253cb5fc7 100644 --- a/lib/libdevctl/event.h +++ b/lib/libdevctl/event.h @@ -95,7 +95,7 @@ public: typedef Event* (BuildMethod)(Type, NVPairMap &, const std::string &); /** Generic Event object factory. */ - static BuildMethod EventBuilder; + static BuildMethod Builder; static Event *CreateEvent(const EventFactory &factory, const std::string &eventString); @@ -189,6 +189,16 @@ public: */ timeval GetTimestamp() const; + /** + * Add a timestamp to the event string, if one does not already exist + * TODO: make this an instance method that operates on the std::map + * instead of the string. We must fix zfsd's CaseFile serialization + * routines first, so that they don't need the raw event string. + * + * \param[in,out] eventString The devd event string to modify + */ + static void TimestampEventString(std::string &eventString); + /** * Access all parsed key => value pairs. */ @@ -277,7 +287,7 @@ class DevfsEvent : public Event { public: /** Specialized Event object factory for Devfs events. */ - static BuildMethod DevfsEventBuilder; + static BuildMethod Builder; virtual Event *DeepCopy() const; @@ -326,7 +336,7 @@ class ZfsEvent : public Event { public: /** Specialized Event object factory for ZFS events. */ - static BuildMethod ZfsEventBuilder; + static BuildMethod Builder; virtual Event *DeepCopy() const; diff --git a/lib/libdevctl/event_factory.cc b/lib/libdevctl/event_factory.cc index 364e0d096876..d705ec8e35d9 100644 --- a/lib/libdevctl/event_factory.cc +++ b/lib/libdevctl/event_factory.cc @@ -88,8 +88,10 @@ EventFactory::Build(Event::Type type, NVPairMap &nvpairs, if (foundMethod != m_registry.end()) buildMethod = foundMethod->second; - if (buildMethod == NULL) + if (buildMethod == NULL) { + delete &nvpairs; return (NULL); + } return (buildMethod(type, nvpairs, eventString)); } diff --git a/lib/libdevctl/exception.cc b/lib/libdevctl/exception.cc index 4d242df29f42..c20c2c5b6b3e 100644 --- a/lib/libdevctl/exception.cc +++ b/lib/libdevctl/exception.cc @@ -37,6 +37,8 @@ #include +#include +#include #include #include