diff options
author | asomers <asomers@FreeBSD.org> | 2016-05-28 17:43:40 +0000 |
---|---|---|
committer | asomers <asomers@FreeBSD.org> | 2016-05-28 17:43:40 +0000 |
commit | 442baa51845cf38dbcfdc44bd8493defdaad630a (patch) | |
tree | b276df22690bfddec70e75c8b9f2f7c8df80cbc6 /lib/libdevdctl | |
parent | da1a7cbaba7d56d77911e9c80b3f82d515ef5e78 (diff) | |
download | FreeBSD-src-442baa51845cf38dbcfdc44bd8493defdaad630a.zip FreeBSD-src-442baa51845cf38dbcfdc44bd8493defdaad630a.tar.gz |
zfsd(8), the ZFS fault management daemon
Add zfsd, which deals with hard drive faults in ZFS pools. It manages
hotspares and replements in drive slots that publish physical paths.
cddl/usr.sbin/zfsd
Add zfsd(8) and its unit tests
cddl/usr.sbin/Makefile
Add zfsd to the build
lib/libdevdctl
A C++ library that helps devd clients process events
lib/Makefile
share/mk/bsd.libnames.mk
share/mk/src.libnames.mk
Add libdevdctl to the build. It's a private library, unusable by
out-of-tree software.
etc/defaults/rc.conf
By default, set zfsd_enable to NO
etc/mtree/BSD.include.dist
Add a directory for libdevdctl's include files
etc/mtree/BSD.tests.dist
Add a directory for zfsd's unit tests
etc/mtree/BSD.var.dist
Add /var/db/zfsd/cases, where zfsd stores case files while it's shut
down.
etc/rc.d/Makefile
etc/rc.d/zfsd
Add zfsd's rc script
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c
Fix the resource.fs.zfs.statechange message. It had a number of
problems:
It was only being emitted on a transition to the HEALTHY state.
That made it impossible for zfsd to take actions based on drives
getting sicker.
It compared the new state to vdev_prevstate, which is the state that
the vdev had the last time it was opened. That doesn't make sense,
because a vdev can change state multiple times without being
reopened.
vdev_set_state contains logic that will change the device's new
state based on various conditions. However, the statechange event
was being posted _before_ that logic took effect. Now it's being
posted after.
Submitted by: gibbs, asomers, mav, allanjude
Reviewed by: mav, delphij
Relnotes: yes
Sponsored by: Spectra Logic Corp, iX Systems
Differential Revision: https://reviews.freebsd.org/D6564
Diffstat (limited to 'lib/libdevdctl')
-rw-r--r-- | lib/libdevdctl/Makefile | 21 | ||||
-rw-r--r-- | lib/libdevdctl/consumer.cc | 258 | ||||
-rw-r--r-- | lib/libdevdctl/consumer.h | 186 | ||||
-rw-r--r-- | lib/libdevdctl/event.cc | 602 | ||||
-rw-r--r-- | lib/libdevdctl/event.h | 423 | ||||
-rw-r--r-- | lib/libdevdctl/event_factory.cc | 99 | ||||
-rw-r--r-- | lib/libdevdctl/event_factory.h | 94 | ||||
-rw-r--r-- | lib/libdevdctl/exception.cc | 125 | ||||
-rw-r--r-- | lib/libdevdctl/exception.h | 168 | ||||
-rw-r--r-- | lib/libdevdctl/guid.cc | 82 | ||||
-rw-r--r-- | lib/libdevdctl/guid.h | 143 | ||||
-rw-r--r-- | lib/libdevdctl/tests/Makefile | 21 | ||||
-rw-r--r-- | lib/libdevdctl/tests/libdevdctl_unittest.cc | 138 |
13 files changed, 2360 insertions, 0 deletions
diff --git a/lib/libdevdctl/Makefile b/lib/libdevdctl/Makefile new file mode 100644 index 0000000..5a18a14 --- /dev/null +++ b/lib/libdevdctl/Makefile @@ -0,0 +1,21 @@ +# $FreeBSD$ + +LIB_CXX= devdctl +INCS= consumer.h \ + event.h \ + event_factory.h \ + exception.h \ + guid.h +SRCS= consumer.cc \ + event.cc \ + event_factory.cc \ + exception.cc \ + guid.cc + +INCSDIR= ${INCLUDEDIR}/devdctl + +WARNS?= 3 +PRIVATELIB= true +SHLIB_MAJOR= 0 + +.include <bsd.lib.mk> diff --git a/lib/libdevdctl/consumer.cc b/lib/libdevdctl/consumer.cc new file mode 100644 index 0000000..6b9822e --- /dev/null +++ b/lib/libdevdctl/consumer.cc @@ -0,0 +1,258 @@ +/*- + * Copyright (c) 2011, 2012, 2013, 2014 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + */ + +/** + * \file consumer.cc + */ + +#include <sys/cdefs.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <syslog.h> +#include <unistd.h> + +#include <cstdarg> +#include <cstring> +#include <list> +#include <map> +#include <string> + +#include "guid.h" +#include "event.h" +#include "event_factory.h" +#include "exception.h" + +#include "consumer.h" + +__FBSDID("$FreeBSD$"); + +/*================================== Macros ==================================*/ +#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) + +/*============================ Namespace Control =============================*/ +using std::string; +namespace DevdCtl +{ + +/*============================= Class Definitions ============================*/ +/*----------------------------- DevdCtl::Consumer ----------------------------*/ +//- Consumer Static Private Data ----------------------------------------------- +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_eventFactory(defBuilder), + m_replayingEvents(false) +{ + m_eventFactory.UpdateRegistry(regEntries, numEntries); +} + +Consumer::~Consumer() +{ + DisconnectFromDevd(); +} + +bool +Consumer::ConnectToDevd() +{ + struct sockaddr_un devdAddr; + int sLen; + int result; + + if (m_devdSockFD != -1) { + /* Already connected. */ + syslog(LOG_DEBUG, "%s: Already connected.", __func__); + return (true); + } + syslog(LOG_INFO, "%s: Connecting to devd.", __func__); + + memset(&devdAddr, 0, sizeof(devdAddr)); + devdAddr.sun_family= AF_UNIX; + strlcpy(devdAddr.sun_path, s_devdSockPath, sizeof(devdAddr.sun_path)); + sLen = SUN_LEN(&devdAddr); + + 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<sockaddr *>(&devdAddr), + sLen); + if (result == -1) { + syslog(LOG_INFO, "Unable to connect to devd"); + DisconnectFromDevd(); + return (false); + } + + syslog(LOG_INFO, "Connection to devd successful"); + return (true); +} + +void +Consumer::DisconnectFromDevd() +{ + if (m_devdSockFD != -1) + syslog(LOG_INFO, "Disconnecting from devd."); + + 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) +{ + EventList::iterator event(m_unconsumedEvents.begin()); + bool replayed_any = (event != m_unconsumedEvents.end()); + + m_replayingEvents = true; + if (replayed_any) + syslog(LOG_INFO, "Started replaying unconsumed events"); + while (event != m_unconsumedEvents.end()) { + bool consumed((*event)->Process()); + if (consumed || discardUnconsumed) { + delete *event; + event = m_unconsumedEvents.erase(event); + } else { + event++; + } + } + if (replayed_any) + syslog(LOG_INFO, "Finished replaying unconsumed events"); + m_replayingEvents = false; +} + +bool +Consumer::SaveEvent(const Event &event) +{ + if (m_replayingEvents) + return (false); + m_unconsumedEvents.push_back(event.DeepCopy()); + return (true); +} + +Event * +Consumer::NextEvent() +{ + if (!Connected()) + return(NULL); + + Event *event(NULL); + try { + string evString; + + evString = ReadEvent(); + if (! evString.empty()) { + Event::TimestampEventString(evString); + event = Event::CreateEvent(m_eventFactory, evString); + } + } catch (const Exception &exp) { + exp.Log(); + DisconnectFromDevd(); + } + return (event); +} + +/* Capture and process buffered events. */ +void +Consumer::ProcessEvents() +{ + Event *event; + while ((event = NextEvent()) != NULL) { + if (event->Process()) + SaveEvent(*event); + delete event; + } +} + +void +Consumer::FlushEvents() +{ + std::string s; + + do + s = ReadEvent(); + while (! s.empty()) ; +} + +bool +Consumer::EventsPending() +{ + struct pollfd fds[1]; + int result; + + do { + fds->fd = m_devdSockFD; + fds->events = POLLIN; + fds->revents = 0; + result = poll(fds, NUM_ELEMENTS(fds), /*timeout*/0); + } while (result == -1 && errno == EINTR); + + if (result == -1) + err(1, "Polling for devd events failed"); + + if ((fds->revents & POLLERR) != 0) + throw Exception("Consumer::EventsPending(): " + "POLLERR detected on devd socket."); + + if ((fds->revents & POLLHUP) != 0) + throw Exception("Consumer::EventsPending(): " + "POLLHUP detected on devd socket."); + + return ((fds->revents & POLLIN) != 0); +} + +} // namespace DevdCtl diff --git a/lib/libdevdctl/consumer.h b/lib/libdevdctl/consumer.h new file mode 100644 index 0000000..721461e --- /dev/null +++ b/lib/libdevdctl/consumer.h @@ -0,0 +1,186 @@ +/*- + * Copyright (c) 2011, 2012, 2013, 2014 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + * + * $FreeBSD$ + */ + +/** + * \file devdctl_consumer.h + */ +#ifndef _DEVDCTL_CONSUMER_H_ +#define _DEVDCTL_CONSUMER_H_ + +/*============================ Namespace Control =============================*/ +namespace DevdCtl +{ + +/*=========================== Forward Declarations ===========================*/ +class Event; +class EventBuffer; +class FDReader; + +/*============================ Class Declarations ============================*/ +/*----------------------------- DevdCtl::Consumer ----------------------------*/ + +/** + */ +class Consumer +{ +public: + Consumer(Event::BuildMethod *defBuilder = NULL, + EventFactory::Record *regEntries = NULL, + size_t numEntries = 0); + virtual ~Consumer(); + + bool Connected() const; + + /** + * Return file descriptor useful for client's wishing to poll(2) + * for new events. + */ + int GetPollFd(); + + /** + * Queue an event for deferred processing or replay. + */ + bool SaveEvent(const Event &event); + + /** + * Reprocess any events saved via the SaveEvent() facility. + * + * \param discardUnconsumed If true, events that are not consumed + * during replay are discarded. + */ + void ReplayUnconsumedEvents(bool discardUnconsumed); + + /** Return an event, if one is available. */ + Event *NextEvent(); + + /** + * Extract events and invoke each event's Process method. + */ + void ProcessEvents(); + + /** Discard all data pending in m_devdSockFD. */ + void FlushEvents(); + + /** + * Test for data pending in m_devdSockFD + * + * \return True if data is pending. Otherwise false. + */ + bool EventsPending(); + + /** + * Open a connection to devd's unix domain socket. + * + * \return True if the connection attempt is successsful. Otherwise + * false. + */ + bool ConnectToDevd(); + + /** + * Close a connection (if any) to devd's unix domain socket. + */ + void DisconnectFromDevd(); + + 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 libdevdctl. + */ + MAX_EVENT_SIZE = 8192, + }; + + static const char s_devdSockPath[]; + + /** + * File descriptor representing the unix domain socket + * connection with devd. + */ + int m_devdSockFD; + + /** + * Reader tied to the devd socket. + */ + FDReader *m_reader; + + /** + * Default EventBuffer connected to m_reader. + */ + EventBuffer *m_eventBuffer; + + EventFactory m_eventFactory; + + /** Queued events for replay. */ + EventList m_unconsumedEvents; + + /** + * Flag controlling whether events can be queued. This boolean + * is set during event replay to ensure that previosuly deferred + * events are not requeued and thus retained forever. + */ + bool m_replayingEvents; +}; + +//- Consumer Const Public Inline Methods --------------------------------------- +inline bool +Consumer::Connected() const +{ + return (m_devdSockFD != -1); +} + +//- Consumer Public Inline Methods --------------------------------------------- +inline int +Consumer::GetPollFd() +{ + return (m_devdSockFD); +} + +inline EventFactory +Consumer::GetFactory() +{ + return (m_eventFactory); +} + +} // namespace DevdCtl +#endif /* _DEVDCTL_CONSUMER_H_ */ diff --git a/lib/libdevdctl/event.cc b/lib/libdevdctl/event.cc new file mode 100644 index 0000000..3c6304b --- /dev/null +++ b/lib/libdevdctl/event.cc @@ -0,0 +1,602 @@ +/*- + * Copyright (c) 2011, 2012, 2013, 2016 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + */ + +/** + * \file event.cc + * + * Implementation of the class hierarchy used to express events + * received via the devdctl API. + */ +#include <sys/cdefs.h> +#include <sys/disk.h> +#include <sys/filio.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <err.h> +#include <fcntl.h> +#include <inttypes.h> +#include <paths.h> +#include <stdlib.h> +#include <syslog.h> +#include <unistd.h> + +#include <cstdarg> +#include <cstring> +#include <iostream> +#include <list> +#include <map> +#include <sstream> +#include <string> + +#include "guid.h" +#include "event.h" +#include "event_factory.h" +#include "exception.h" + +__FBSDID("$FreeBSD$"); + +/*================================== Macros ==================================*/ +#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) + +/*============================ Namespace Control =============================*/ +using std::cout; +using std::endl; +using std::string; +using std::stringstream; + +namespace DevdCtl +{ + +/*=========================== Class Implementations ==========================*/ +/*----------------------------------- Event ----------------------------------*/ +//- Event Static Protected Data ------------------------------------------------ +const string Event::s_theEmptyString; + +Event::EventTypeRecord Event::s_typeTable[] = +{ + { Event::NOTIFY, "Notify" }, + { Event::NOMATCH, "No Driver Match" }, + { Event::ATTACH, "Attach" }, + { Event::DETACH, "Detach" } +}; + +//- Event Static Public Methods ------------------------------------------------ +Event * +Event::Builder(Event::Type type, NVPairMap &nvPairs, + const string &eventString) +{ + return (new Event(type, nvPairs, eventString)); +} + +Event * +Event::CreateEvent(const EventFactory &factory, const string &eventString) +{ + NVPairMap &nvpairs(*new NVPairMap); + Type type(static_cast<Event::Type>(eventString[0])); + + try { + ParseEventString(type, eventString, nvpairs); + } catch (const ParseException &exp) { + if (exp.GetType() == ParseException::INVALID_FORMAT) + exp.Log(); + return (NULL); + } + + /* + * Allow entries in our table for events with no system specified. + * These entries should specify the string "none". + */ + NVPairMap::iterator system_item(nvpairs.find("system")); + if (system_item == nvpairs.end()) + nvpairs["system"] = "none"; + + return (factory.Build(type, nvpairs, eventString)); +} + +bool +Event::DevName(std::string &name) const +{ + return (false); +} + +/* TODO: simplify this function with C++-11 <regex> methods */ +bool +Event::IsDiskDev() const +{ + const int numDrivers = 2; + static const char *diskDevNames[numDrivers] = + { + "da", + "ada" + }; + const char **dName; + string devName; + + if (! DevName(devName)) + return false; + + size_t find_start = devName.rfind('/'); + if (find_start == string::npos) { + find_start = 0; + } else { + /* Just after the last '/'. */ + find_start++; + } + + for (dName = &diskDevNames[0]; + dName <= &diskDevNames[numDrivers - 1]; dName++) { + + size_t loc(devName.find(*dName, find_start)); + if (loc == find_start) { + size_t prefixLen(strlen(*dName)); + + if (devName.length() - find_start >= prefixLen + && isdigit(devName[find_start + prefixLen])) + return (true); + } + } + + return (false); +} + +const char * +Event::TypeToString(Event::Type type) +{ + EventTypeRecord *rec(s_typeTable); + EventTypeRecord *lastRec(s_typeTable + NUM_ELEMENTS(s_typeTable) - 1); + + for (; rec <= lastRec; rec++) { + if (rec->m_type == type) + return (rec->m_typeName); + } + return ("Unknown"); +} + +//- Event Public Methods ------------------------------------------------------- +const string & +Event::Value(const string &varName) const +{ + NVPairMap::const_iterator item(m_nvPairs.find(varName)); + if (item == m_nvPairs.end()) + return (s_theEmptyString); + + return (item->second); +} + +bool +Event::Contains(const string &varName) const +{ + return (m_nvPairs.find(varName) != m_nvPairs.end()); +} + +string +Event::ToString() const +{ + stringstream result; + + NVPairMap::const_iterator devName(m_nvPairs.find("device-name")); + if (devName != m_nvPairs.end()) + result << devName->second << ": "; + + NVPairMap::const_iterator systemName(m_nvPairs.find("system")); + if (systemName != m_nvPairs.end() + && systemName->second != "none") + result << systemName->second << ": "; + + result << TypeToString(GetType()) << ' '; + + for (NVPairMap::const_iterator curVar = m_nvPairs.begin(); + curVar != m_nvPairs.end(); curVar++) { + if (curVar == devName || curVar == systemName) + continue; + + result << ' ' + << curVar->first << "=" << curVar->second; + } + result << endl; + + return (result.str()); +} + +void +Event::Print() const +{ + cout << ToString() << std::flush; +} + +void +Event::Log(int priority) const +{ + syslog(priority, "%s", ToString().c_str()); +} + +//- Event Virtual Public Methods ----------------------------------------------- +Event::~Event() +{ + delete &m_nvPairs; +} + +Event * +Event::DeepCopy() const +{ + return (new Event(*this)); +} + +bool +Event::Process() const +{ + return (false); +} + +timeval +Event::GetTimestamp() const +{ + timeval tv_timestamp; + struct tm tm_timestamp; + + if (!Contains("timestamp")) { + throw Exception("Event contains no timestamp: %s", + m_eventString.c_str()); + } + strptime(Value(string("timestamp")).c_str(), "%s", &tm_timestamp); + tv_timestamp.tv_sec = mktime(&tm_timestamp); + tv_timestamp.tv_usec = 0; + return (tv_timestamp); +} + +bool +Event::DevPath(std::string &path) const +{ + string devName; + + if (!DevName(devName)) + return (false); + + string devPath(_PATH_DEV + devName); + int devFd(open(devPath.c_str(), O_RDONLY)); + if (devFd == -1) + return (false); + + /* Normalize the device name in case the DEVFS event is for a link. */ + devName = fdevname(devFd); + path = _PATH_DEV + devName; + + close(devFd); + + return (true); +} + +bool +Event::PhysicalPath(std::string &path) const +{ + string devPath; + + if (!DevPath(devPath)) + return (false); + + int devFd(open(devPath.c_str(), O_RDONLY)); + if (devFd == -1) + return (false); + + char physPath[MAXPATHLEN]; + physPath[0] = '\0'; + bool result(ioctl(devFd, DIOCGPHYSPATH, physPath) == 0); + close(devFd); + if (result) + path = physPath; + return (result); +} + +//- Event Protected Methods ---------------------------------------------------- +Event::Event(Type type, NVPairMap &map, const string &eventString) + : m_type(type), + m_nvPairs(map), + m_eventString(eventString) +{ +} + +Event::Event(const Event &src) + : m_type(src.m_type), + m_nvPairs(*new NVPairMap(src.m_nvPairs)), + m_eventString(src.m_eventString) +{ +} + +void +Event::ParseEventString(Event::Type type, + const string &eventString, + NVPairMap& nvpairs) +{ + size_t start; + size_t end; + + switch (type) { + case ATTACH: + case DETACH: + + /* + * <type><device-name><unit> <pnpvars> \ + * at <location vars> <pnpvars> \ + * on <parent> + * + * Handle all data that doesn't conform to the + * "name=value" format, and let the generic parser + * below handle the rest. + * + * Type is a single char. Skip it. + */ + start = 1; + end = eventString.find_first_of(" \t\n", start); + if (end == string::npos) + throw ParseException(ParseException::INVALID_FORMAT, + eventString, start); + + nvpairs["device-name"] = eventString.substr(start, end - start); + + start = eventString.find(" on ", end); + if (end == string::npos) + throw ParseException(ParseException::INVALID_FORMAT, + eventString, start); + start += 4; + end = eventString.find_first_of(" \t\n", start); + nvpairs["parent"] = eventString.substr(start, end); + break; + case NOTIFY: + break; + case NOMATCH: + throw ParseException(ParseException::DISCARDED_EVENT_TYPE, + eventString); + default: + throw ParseException(ParseException::UNKNOWN_EVENT_TYPE, + eventString); + } + + /* Process common "key=value" format. */ + for (start = 1; start < eventString.length(); start = end + 1) { + + /* Find the '=' in the middle of the key/value pair. */ + end = eventString.find('=', start); + if (end == string::npos) + break; + + /* + * Find the start of the key by backing up until + * we hit whitespace or '!' (event type "notice"). + * Due to the devdctl format, all key/value pair must + * start with one of these two characters. + */ + start = eventString.find_last_of("! \t\n", end); + if (start == string::npos) + throw ParseException(ParseException::INVALID_FORMAT, + eventString, end); + start++; + string key(eventString.substr(start, end - start)); + + /* + * Walk forward from the '=' until either we exhaust + * the buffer or we hit whitespace. + */ + start = end + 1; + if (start >= eventString.length()) + throw ParseException(ParseException::INVALID_FORMAT, + eventString, end); + end = eventString.find_first_of(" \t\n", start); + if (end == string::npos) + end = eventString.length() - 1; + string value(eventString.substr(start, end - start)); + + nvpairs[key] = value; + } +} + +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; + char timebuf[bufsize]; + + size_t eventEnd(eventString.find_last_not_of('\n') + 1); + if (gettimeofday(&now, NULL) != 0) + err(1, "gettimeofday"); + snprintf(timebuf, bufsize, " timestamp=%"PRId64, + (int64_t) now.tv_sec); + eventString.insert(eventEnd, timebuf); + } + } +} + +/*-------------------------------- DevfsEvent --------------------------------*/ +//- DevfsEvent Static Public Methods ------------------------------------------- +Event * +DevfsEvent::Builder(Event::Type type, NVPairMap &nvPairs, + const string &eventString) +{ + return (new DevfsEvent(type, nvPairs, eventString)); +} + +//- DevfsEvent Static Protected Methods ---------------------------------------- +bool +DevfsEvent::IsWholeDev(const string &devName) +{ + string::const_iterator i(devName.begin()); + + size_t start = devName.rfind('/'); + if (start == string::npos) { + start = 0; + } else { + /* Just after the last '/'. */ + start++; + } + i += start; + + /* alpha prefix followed only by digits. */ + for (; i < devName.end() && !isdigit(*i); i++) + ; + + if (i == devName.end()) + return (false); + + for (; i < devName.end() && isdigit(*i); i++) + ; + + return (i == devName.end()); +} + +//- DevfsEvent Virtual Public Methods ------------------------------------------ +Event * +DevfsEvent::DeepCopy() const +{ + return (new DevfsEvent(*this)); +} + +bool +DevfsEvent::Process() const +{ + return (true); +} + +//- DevfsEvent Public Methods -------------------------------------------------- +bool +DevfsEvent::IsWholeDev() const +{ + string devName; + + return (DevName(devName) && IsDiskDev() && IsWholeDev(devName)); +} + +bool +DevfsEvent::DevName(std::string &name) const +{ + if (Value("subsystem") != "CDEV") + return (false); + + name = Value("cdev"); + return (!name.empty()); +} + +//- DevfsEvent Protected Methods ----------------------------------------------- +DevfsEvent::DevfsEvent(Event::Type type, NVPairMap &nvpairs, + const string &eventString) + : Event(type, nvpairs, eventString) +{ +} + +DevfsEvent::DevfsEvent(const DevfsEvent &src) + : Event(src) +{ +} + +/*--------------------------------- GeomEvent --------------------------------*/ +//- GeomEvent Static Public Methods -------------------------------------------- +Event * +GeomEvent::Builder(Event::Type type, NVPairMap &nvpairs, + const string &eventString) +{ + return (new GeomEvent(type, nvpairs, eventString)); +} + +//- GeomEvent Virtual Public Methods ------------------------------------------- +Event * +GeomEvent::DeepCopy() const +{ + return (new GeomEvent(*this)); +} + +bool +GeomEvent::DevName(std::string &name) const +{ + name = Value("devname"); + return (!name.empty()); +} + + +//- GeomEvent Protected Methods ------------------------------------------------ +GeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs, + const string &eventString) + : Event(type, nvpairs, eventString), + m_devname(Value("devname")) +{ +} + +GeomEvent::GeomEvent(const GeomEvent &src) + : Event(src), + m_devname(src.m_devname) +{ +} + +/*--------------------------------- ZfsEvent ---------------------------------*/ +//- ZfsEvent Static Public Methods --------------------------------------------- +Event * +ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs, + const string &eventString) +{ + return (new ZfsEvent(type, nvpairs, eventString)); +} + +//- ZfsEvent Virtual Public Methods -------------------------------------------- +Event * +ZfsEvent::DeepCopy() const +{ + return (new ZfsEvent(*this)); +} + +bool +ZfsEvent::DevName(std::string &name) const +{ + return (false); +} + +//- ZfsEvent Protected Methods ------------------------------------------------- +ZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs, + const string &eventString) + : Event(type, nvpairs, eventString), + m_poolGUID(Guid(Value("pool_guid"))), + m_vdevGUID(Guid(Value("vdev_guid"))) +{ +} + +ZfsEvent::ZfsEvent(const ZfsEvent &src) + : Event(src), + m_poolGUID(src.m_poolGUID), + m_vdevGUID(src.m_vdevGUID) +{ +} + +} // namespace DevdCtl diff --git a/lib/libdevdctl/event.h b/lib/libdevdctl/event.h new file mode 100644 index 0000000..796029a --- /dev/null +++ b/lib/libdevdctl/event.h @@ -0,0 +1,423 @@ +/*- + * Copyright (c) 2011, 2012, 2013, 2016 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + * + * $FreeBSD$ + */ + +/** + * \file devdctl_event.h + * + * \brief Class hierarchy used to express events received via + * the devdctl API. + */ + +#ifndef _DEVDCTL_EVENT_H_ +#define _DEVDCTL_EVENT_H_ + +/*============================ Namespace Control =============================*/ +namespace DevdCtl +{ + +/*=========================== Forward Declarations ===========================*/ +class EventFactory; + +/*============================= Class Definitions ============================*/ +/*-------------------------------- NVPairMap ---------------------------------*/ +/** + * NVPairMap is a specialization of the standard map STL container. + */ +typedef std::map<std::string, std::string> NVPairMap; + +/*----------------------------------- Event ----------------------------------*/ +/** + * \brief Container for the name => value pairs that comprise the content of + * a device control event. + * + * All name => value data for events can be accessed via the Contains() + * and Value() methods. name => value pairs for data not explicitly + * received as a name => value pair are synthesized during parsing. For + * example, ATTACH and DETACH events have "device-name" and "parent" + * name => value pairs added. + */ +class Event +{ + friend class EventFactory; + +public: + /** Event type */ + enum Type { + /** Generic event notification. */ + NOTIFY = '!', + + /** A driver was not found for this device. */ + NOMATCH = '?', + + /** A bus device instance has been added. */ + ATTACH = '+', + + /** A bus device instance has been removed. */ + DETACH = '-' + }; + + /** + * Factory method type to construct an Event given + * the type of event and an NVPairMap populated from + * the event string received from devd. + */ + typedef Event* (BuildMethod)(Type, NVPairMap &, const std::string &); + + /** Generic Event object factory. */ + static BuildMethod Builder; + + static Event *CreateEvent(const EventFactory &factory, + const std::string &eventString); + + /** + * Returns the devname, if any, associated with the event + * + * \param name Devname, returned by reference + * \return True iff the event contained a devname + */ + virtual bool DevName(std::string &name) const; + + /** + * Returns the absolute pathname of the device associated with this + * event. + * + * \param name Devname, returned by reference + * \return True iff the event contained a devname + */ + bool DevPath(std::string &path) const; + + /** + * Returns true iff this event refers to a disk device + */ + bool IsDiskDev() const; + + /** Returns the physical path of the device, if any + * + * \param path Physical path, returned by reference + * \return True iff the event contains a device with a physical + * path + */ + bool PhysicalPath(std::string &path) const; + + /** + * Provide a user friendly string representation of an + * event type. + * + * \param type The type of event to map to a string. + * + * \return A user friendly string representing the input type. + */ + static const char *TypeToString(Type type); + + /** + * Determine the availability of a name => value pair by name. + * + * \param name The key name to search for in this event instance. + * + * \return true if the specified key is available in this + * event, otherwise false. + */ + bool Contains(const std::string &name) const; + + /** + * \param key The name of the key for which to retrieve its + * associated value. + * + * \return A const reference to the string representing the + * value associated with key. + * + * \note For key's with no registered value, the empty string + * is returned. + */ + const std::string &Value(const std::string &key) const; + + /** + * Get the type of this event instance. + * + * \return The type of this event instance. + */ + Type GetType() const; + + /** + * Get the orginal DevdCtl event string for this event. + * + * \return The DevdCtl event string. + */ + const std::string &GetEventString() const; + + /** + * Convert the event instance into a string suitable for + * printing to the console or emitting to syslog. + * + * \return A string of formatted event data. + */ + std::string ToString() const; + + /** + * Pretty-print this event instance to cout. + */ + void Print() const; + + /** + * Pretty-print this event instance to syslog. + * + * \param priority The logging priority/facility. + * See syslog(3). + */ + void Log(int priority) const; + + /** + * Create and return a fully independent clone + * of this event. + */ + virtual Event *DeepCopy() const; + + /** Destructor */ + virtual ~Event(); + + /** + * Interpret and perform any actions necessary to + * consume the event. + * + * \return True if this event should be queued for later reevaluation + */ + virtual bool Process() const; + + /** + * Get the time that the event was created + */ + 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. + */ + const NVPairMap &GetMap() const; + +protected: + /** Table entries used to map a type to a user friendly string. */ + struct EventTypeRecord + { + Type m_type; + const char *m_typeName; + }; + + /** + * Constructor + * + * \param type The type of event to create. + */ + Event(Type type, NVPairMap &map, const std::string &eventString); + + /** Deep copy constructor. */ + Event(const Event &src); + + /** Always empty string returned when NVPairMap lookups fail. */ + static const std::string s_theEmptyString; + + /** Unsorted table of event types. */ + static EventTypeRecord s_typeTable[]; + + /** The type of this event. */ + const Type m_type; + + /** + * Event attribute storage. + * + * \note Although stored by reference (since m_nvPairs can + * never be NULL), the NVPairMap referenced by this field + * is dynamically allocated and owned by this event object. + * m_nvPairs must be deleted at event desctruction. + */ + NVPairMap &m_nvPairs; + + /** + * The unaltered event string, as received from devd, used to + * create this event object. + */ + std::string m_eventString; + +private: + /** + * Ingest event data from the supplied string. + * + * \param[in] eventString The string of devd event data to parse. + * \param[out] nvpairs Returns the parsed data + */ + static void ParseEventString(Type type, const std::string &eventString, + NVPairMap &nvpairs); +}; + +inline Event::Type +Event::GetType() const +{ + return (m_type); +} + +inline const std::string & +Event::GetEventString() const +{ + return (m_eventString); +} + +inline const NVPairMap & +Event::GetMap() const +{ + return (m_nvPairs); +} + +/*--------------------------------- EventList --------------------------------*/ +/** + * EventList is a specialization of the standard list STL container. + */ +typedef std::list<Event *> EventList; + +/*-------------------------------- DevfsEvent --------------------------------*/ +class DevfsEvent : public Event +{ +public: + /** Specialized Event object factory for Devfs events. */ + static BuildMethod Builder; + + virtual Event *DeepCopy() const; + + /** + * Interpret and perform any actions necessary to + * consume the event. + * \return True if this event should be queued for later reevaluation + */ + virtual bool Process() const; + + bool IsWholeDev() const; + virtual bool DevName(std::string &name) const; + +protected: + /** + * Given the device name of a disk, determine if the device + * represents the whole device, not just a partition. + * + * \param devName Device name of disk device to test. + * + * \return True if the device name represents the whole device. + * Otherwise false. + */ + static bool IsWholeDev(const std::string &devName); + + /** DeepCopy Constructor. */ + DevfsEvent(const DevfsEvent &src); + + /** Constructor */ + DevfsEvent(Type, NVPairMap &, const std::string &); +}; + +/*--------------------------------- GeomEvent --------------------------------*/ +class GeomEvent : public Event +{ +public: + /** Specialized Event object factory for GEOM events. */ + static BuildMethod Builder; + + virtual Event *DeepCopy() const; + + virtual bool DevName(std::string &name) const; + + const std::string &DeviceName() const; + +protected: + /** Constructor */ + GeomEvent(Type, NVPairMap &, const std::string &); + + /** Deep copy constructor. */ + GeomEvent(const GeomEvent &src); + + std::string m_devname; +}; + +/*--------------------------------- ZfsEvent ---------------------------------*/ +class ZfsEvent : public Event +{ +public: + /** Specialized Event object factory for ZFS events. */ + static BuildMethod Builder; + + virtual Event *DeepCopy() const; + + virtual bool DevName(std::string &name) const; + + const std::string &PoolName() const; + Guid PoolGUID() const; + Guid VdevGUID() const; + +protected: + /** Constructor */ + ZfsEvent(Type, NVPairMap &, const std::string &); + + /** Deep copy constructor. */ + ZfsEvent(const ZfsEvent &src); + + Guid m_poolGUID; + Guid m_vdevGUID; +}; + +//- ZfsEvent Inline Public Methods -------------------------------------------- +inline const std::string& +ZfsEvent::PoolName() const +{ + /* The pool name is reported as the subsystem of ZFS events. */ + return (Value("subsystem")); +} + +inline Guid +ZfsEvent::PoolGUID() const +{ + return (m_poolGUID); +} + +inline Guid +ZfsEvent::VdevGUID() const +{ + return (m_vdevGUID); +} + +} // namespace DevdCtl +#endif /*_DEVDCTL_EVENT_H_ */ diff --git a/lib/libdevdctl/event_factory.cc b/lib/libdevdctl/event_factory.cc new file mode 100644 index 0000000..3901fd5 --- /dev/null +++ b/lib/libdevdctl/event_factory.cc @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2013 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + */ + +/** + * \file event_factory.cc + */ +#include <sys/cdefs.h> +#include <sys/time.h> + +#include <list> +#include <map> +#include <string> + +#include "guid.h" +#include "event.h" +#include "event_factory.h" + +__FBSDID("$FreeBSD$"); + +/*================================== Macros ==================================*/ +#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) + +/*============================ Namespace Control =============================*/ +namespace DevdCtl +{ + +/*=========================== Class Implementations ==========================*/ +/*------------------------------- EventFactory -------------------------------*/ +//- Event Public Methods ------------------------------------------------------- +EventFactory::EventFactory(Event::BuildMethod *defaultBuildMethod) + : m_defaultBuildMethod(defaultBuildMethod) +{ +} + +void +EventFactory::UpdateRegistry(Record regEntries[], size_t numEntries) +{ + EventFactory::Record *rec(regEntries); + EventFactory::Record *lastRec(rec + numEntries - 1); + + for (; rec <= lastRec; rec++) { + Key key(rec->m_type, rec->m_subsystem); + + if (rec->m_buildMethod == NULL) + m_registry.erase(key); + else + m_registry[key] = rec->m_buildMethod; + } +} + +Event * +EventFactory::Build(Event::Type type, NVPairMap &nvpairs, + const std::string eventString) const +{ + Key key(type, nvpairs["system"]); + Event::BuildMethod *buildMethod(m_defaultBuildMethod); + + Registry::const_iterator foundMethod(m_registry.find(key)); + if (foundMethod != m_registry.end()) + buildMethod = foundMethod->second; + + if (buildMethod == NULL) { + delete &nvpairs; + return (NULL); + } + + return (buildMethod(type, nvpairs, eventString)); +} + +} // namespace DevdCtl diff --git a/lib/libdevdctl/event_factory.h b/lib/libdevdctl/event_factory.h new file mode 100644 index 0000000..e23332c --- /dev/null +++ b/lib/libdevdctl/event_factory.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2013 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + * + * $FreeBSD$ + */ + +/** + * \file devdctl_event_factory.h + */ + +#ifndef _DEVDCTL_EVENT_FACTORY_H_ +#define _DEVDCTL_EVENT_FACTORY_H_ + +/*============================ Namespace Control =============================*/ +namespace DevdCtl +{ + +/*============================= Class Definitions ============================*/ +/*------------------------------- EventFactory -------------------------------*/ +/** + * \brief Container for "event type" => "event object" creation methods. + */ +class EventFactory +{ +public: + /** + * Event creation handlers are matched by event type and a + * string representing the system emitting the event. + */ + typedef std::pair<Event::Type, std::string> Key; + + /** Map type for Factory method lookups. */ + typedef std::map<Key, Event::BuildMethod *> Registry; + + /** Table record of factory methods to add to our registry. */ + struct Record + { + Event::Type m_type; + const char *m_subsystem; + Event::BuildMethod *m_buildMethod; + }; + + const Registry &GetRegistry() const; + Event *Build(Event::Type type, NVPairMap &nvpairs, + const std::string eventString) const; + + EventFactory(Event::BuildMethod *defaultBuildMethod = NULL); + + void UpdateRegistry(Record regEntries[], size_t numEntries); + + +protected: + /** Registry of event factory methods providing O(log(n)) lookup. */ + Registry m_registry; + + Event::BuildMethod *m_defaultBuildMethod; +}; + +inline const EventFactory::Registry & +EventFactory::GetRegistry() const +{ + return (m_registry); +} + +} // namespace DevdCtl +#endif /*_DEVDCTL_EVENT_FACTORY_H_ */ diff --git a/lib/libdevdctl/exception.cc b/lib/libdevdctl/exception.cc new file mode 100644 index 0000000..4dc8cf5 --- /dev/null +++ b/lib/libdevdctl/exception.cc @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2011, 2012, 2013, 2014 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + */ + +/** + * \file exception.cc + */ +#include <sys/cdefs.h> + +#include <syslog.h> + +#include <cstdio> +#include <cstdarg> +#include <sstream> +#include <string> + +#include "exception.h" + +__FBSDID("$FreeBSD$"); + +/*============================ Namespace Control =============================*/ +using std::string; +using std::stringstream; +using std::endl; +namespace DevdCtl +{ + +/*=========================== Class Implementations ==========================*/ +/*--------------------------------- Exception --------------------------------*/ +void +Exception::FormatLog(const char *fmt, va_list ap) +{ + char buf[256]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + m_log = buf; +} + +Exception::Exception(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + FormatLog(fmt, ap); + va_end(ap); +} + +Exception::Exception() +{ +} + +void +Exception::Log() const +{ + syslog(LOG_ERR, "%s", m_log.c_str()); +} + +/*------------------------------ ParseException ------------------------------*/ +//- ParseException Inline Public Methods --------------------------------------- +ParseException::ParseException(Type type, const std::string &parsedBuffer, + size_t offset) + : Exception(), + m_type(type), + m_parsedBuffer(parsedBuffer), + m_offset(offset) +{ + stringstream logstream; + + logstream << "Parsing "; + + switch (Type()) { + case INVALID_FORMAT: + logstream << "invalid format "; + break; + case DISCARDED_EVENT_TYPE: + logstream << "discarded event "; + break; + case UNKNOWN_EVENT_TYPE: + logstream << "unknown event "; + break; + default: + break; + } + logstream << "exception on buffer: \'"; + if (GetOffset() == 0) { + logstream << m_parsedBuffer << '\'' << endl; + } else { + string markedBuffer(m_parsedBuffer); + + markedBuffer.insert(GetOffset(), "<HERE-->"); + logstream << markedBuffer << '\'' << endl; + } + + GetString() = logstream.str(); +} + +} // namespace DevdCtl diff --git a/lib/libdevdctl/exception.h b/lib/libdevdctl/exception.h new file mode 100644 index 0000000..9f4403c --- /dev/null +++ b/lib/libdevdctl/exception.h @@ -0,0 +1,168 @@ +/*- + * Copyright (c) 2011, 2012, 2013 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + * + * $FreeBSD$ + */ + +/** + * \file zfsd_exception.h + * + * Definition of the ZfsdException class hierarchy. All exceptions + * explicitly thrown by Zfsd are defined here. + */ +#ifndef _DEVDCTL_EXCEPTION_H_ +#define _DEVDCTL_EXCEPTION_H_ + +/*============================ Namespace Control =============================*/ +namespace DevdCtl +{ + +/*============================= Class Definitions ============================*/ + +/*--------------------------------- Exception --------------------------------*/ +/** + * \brief Class allowing unified reporting/logging of exceptional events. + */ +class Exception +{ +public: + /** + * \brief Exception constructor allowing arbitrary string + * data to be reported. + * + * \param fmt Printf-like string format specifier. + */ + Exception(const char *fmt, ...); + + /** + * \brief Augment/Modify a Exception's string data. + */ + std::string& GetString(); + + /** + * \brief Emit exception data to syslog(3). + */ + virtual void Log() const; + +protected: + Exception(); + + /** + * \brief Convert exception string format and arguments provided + * in event constructors into a linear string. + */ + void FormatLog(const char *fmt, va_list ap); + + std::string m_log; +}; + +inline std::string & +Exception::GetString() +{ + return (m_log); +} + +/*------------------------------ ParseException ------------------------------*/ +/** + * Exception thrown when an event string is not converted to an actionable + * Event object. + */ +class ParseException : public Exception +{ +public: + enum Type + { + /** Improperly formatted event string encountered. */ + INVALID_FORMAT, + + /** No handlers for this event type. */ + DISCARDED_EVENT_TYPE, + + /** Unhandled event type. */ + UNKNOWN_EVENT_TYPE + }; + + /** + * Constructor + * + * \param type The type of this exception. + * \param parsedBuffer The parsing buffer active at the time of + * the exception. + * \param offset The location in the parse buffer where this + * exception occurred. + */ + ParseException(Type type, const std::string &parsedBuffer, + size_t offset = 0); + + /** + * Accessor + * + * \return The classification for this exception. + */ + Type GetType() const; + + /** + * Accessor + * + * \return The offset into the event string where this exception + * occurred. + */ + size_t GetOffset() const; + +private: + /** The type of this exception. */ + Type m_type; + + /** The parsing buffer that was active at the time of the exception. */ + const std::string m_parsedBuffer; + + /** + * The offset into the event string buffer from where this + * exception was triggered. + */ + size_t m_offset; +}; + +//- ParseException Inline Const Public Methods --------------------------------- +inline ParseException::Type +ParseException::GetType() const +{ + return (m_type); +} + +inline size_t +ParseException::GetOffset() const +{ + return (m_offset); +} + +} // namespace DevdCtl +#endif /* _DEVDCTL_EXCEPTION_H_ */ diff --git a/lib/libdevdctl/guid.cc b/lib/libdevdctl/guid.cc new file mode 100644 index 0000000..42d326f --- /dev/null +++ b/lib/libdevdctl/guid.cc @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2012, 2013 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Alan Somers (Spectra Logic Corporation) + * + * $FreeBSD$ + */ + +/** + * \file guid.cc + * + * Implementation of the Guid class. + */ +#include <sys/cdefs.h> + +#include <stdlib.h> +#include <limits.h> +#include <inttypes.h> + +#include <iostream> +#include <string> + +#include "guid.h" + +__FBSDID("$FreeBSD$"); +/*============================ Namespace Control =============================*/ +using std::string; +namespace DevdCtl +{ + +/*=========================== Class Implementations ==========================*/ +/*----------------------------------- Guid -----------------------------------*/ +Guid::Guid(const string &guidString) +{ + if (guidString.empty()) { + m_GUID = INVALID_GUID; + } else { + /* + * strtoumax() returns zero on conversion failure + * which nicely matches our choice for INVALID_GUID. + */ + m_GUID = (uint64_t)strtoumax(guidString.c_str(), NULL, 0); + } +} + +std::ostream& +operator<< (std::ostream& out, Guid g) +{ + if (g.IsValid()) + out << (uint64_t)g; + else + out << "None"; + return (out); +} + +} // namespace DevdCtl diff --git a/lib/libdevdctl/guid.h b/lib/libdevdctl/guid.h new file mode 100644 index 0000000..ede414b --- /dev/null +++ b/lib/libdevdctl/guid.h @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2012, 2013 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Alan Somers (Spectra Logic Corporation) + * + * $FreeBSD$ + */ + +/** + * \file devdctl_guid.h + * + * Definition of the Guid class. + */ +#ifndef _DEVDCTL_GUID_H_ +#define _DEVDCTL_GUID_H_ + +/*============================ Namespace Control =============================*/ +namespace DevdCtl +{ + +/*============================= Class Definitions ============================*/ +/*----------------------------------- Guid -----------------------------------*/ +/** + * \brief Object that represents guids. + * + * It can generally be manipulated as a uint64_t, but with a special + * value INVALID_GUID that does not equal any valid guid. + * + * As of this writing, this class is only used to represent ZFS + * guids in events and spa_generate_guid() in spa_misc.c explicitly + * refuses to return a guid of 0. So this class uses 0 as the value + * for INVALID_GUID. In the future, if 0 is allowed to be a valid + * guid, the implementation of this class must change. + */ +class Guid +{ +public: + /* Constructors */ + Guid(); + Guid(uint64_t guid); + Guid(const std::string &guid); + + /* Assignment */ + Guid& operator=(const Guid& rhs); + + /* Test the validity of this guid. */ + bool IsValid() const; + + /* Comparison to other Guid operators */ + bool operator==(const Guid& rhs) const; + bool operator!=(const Guid& rhs) const; + + /* Integer conversion operators */ + operator uint64_t() const; + operator bool() const; + + static const uint64_t INVALID_GUID = 0; +protected: + /* The integer value of the GUID. */ + uint64_t m_GUID; +}; + +//- Guid Inline Public Methods ------------------------------------------------ +inline +Guid::Guid() + : m_GUID(INVALID_GUID) +{ +} + +inline +Guid::Guid(uint64_t guid) + : m_GUID(guid) +{ +} + +inline Guid& +Guid::operator=(const Guid &rhs) +{ + m_GUID = rhs.m_GUID; + return (*this); +} + +inline bool +Guid::IsValid() const +{ + return (m_GUID != INVALID_GUID); +} + +inline bool +Guid::operator==(const Guid& rhs) const +{ + return (m_GUID == rhs.m_GUID); +} + +inline bool +Guid::operator!=(const Guid& rhs) const +{ + return (m_GUID != rhs.m_GUID); +} + +inline +Guid::operator uint64_t() const +{ + return (m_GUID); +} + +inline +Guid::operator bool() const +{ + return (m_GUID != INVALID_GUID); +} + +/** Convert the GUID into its string representation */ +std::ostream& operator<< (std::ostream& out, Guid g); + +} // namespace DevdCtl +#endif /* _DEVDCTL_GUID_H_ */ diff --git a/lib/libdevdctl/tests/Makefile b/lib/libdevdctl/tests/Makefile new file mode 100644 index 0000000..3bbbd0d --- /dev/null +++ b/lib/libdevdctl/tests/Makefile @@ -0,0 +1,21 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/lib/libdevdctl + +.PATH: ${.CURDIR}/.. + +PLAIN_TESTS_CXX= libdevdctl_unittest + +SRCS.libdevdctl_unittest+= event_factory.cc \ + libdevdctl_unittest.cc \ + event.cc exception.cc \ + guid.cc +CFLAGS.libdevdctl_unittest+= -I ${LOCALBASE}/include -D_THREAD_SAFE -pthread +DPADD.libdevdctl_unittest+= ${LIBDEVDCTL} +LDADD.libdevdctl_unittest+= -L ${LOCALBASE}/lib -D_THREAD_SAFE -pthread -lgtest -lgtest_main + +# Googletest options +LOCALBASE?= /usr/local + +WARNS?= 3 +.include <bsd.test.mk> diff --git a/lib/libdevdctl/tests/libdevdctl_unittest.cc b/lib/libdevdctl/tests/libdevdctl_unittest.cc new file mode 100644 index 0000000..4f69cb6 --- /dev/null +++ b/lib/libdevdctl/tests/libdevdctl_unittest.cc @@ -0,0 +1,138 @@ +/*- + * Copyright (c) 2016 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * Authors: Alan Somers (Spectra Logic Corporation) + * + * $FreeBSD$ + */ + +#include <gtest/gtest.h> + +#include <list> +#include <map> +#include <string> + +#include <devdctl/guid.h> +#include <devdctl/event.h> +#include <devdctl/event_factory.h> + +using namespace DevdCtl; +using namespace std; +using namespace testing; + +#define REGISTRY_SIZE 2 + +struct DevNameTestParams +{ + const char* evs; + bool is_disk; + const char* devname; +}; + +class DevNameTest : public TestWithParam<DevNameTestParams>{ +protected: + virtual void SetUp() + { + m_factory = new EventFactory(); + m_factory->UpdateRegistry(s_registry, REGISTRY_SIZE); + } + + virtual void TearDown() + { + if (m_ev) delete m_ev; + if (m_factory) delete m_factory; + } + + EventFactory *m_factory; + Event *m_ev; + static EventFactory::Record s_registry[REGISTRY_SIZE]; +}; + +DevdCtl::EventFactory::Record DevNameTest::s_registry[REGISTRY_SIZE] = { + { Event::NOTIFY, "DEVFS", &DevfsEvent::Builder }, + { Event::NOTIFY, "GEOM", &GeomEvent::Builder } +}; + +TEST_P(DevNameTest, TestDevname) { + std::string devname; + DevNameTestParams param = GetParam(); + + string evString(param.evs); + m_ev = Event::CreateEvent(*m_factory, evString); + m_ev->DevName(devname); + EXPECT_STREQ(param.devname, devname.c_str()); +} + +TEST_P(DevNameTest, TestIsDiskDev) { + DevNameTestParams param = GetParam(); + + string evString(param.evs); + m_ev = Event::CreateEvent(*m_factory, evString); + EXPECT_EQ(param.is_disk, m_ev->IsDiskDev()); +} + +/* TODO: clean this up using C++-11 uniform initializers */ +INSTANTIATE_TEST_CASE_P(IsDiskDevTestInstantiation, DevNameTest, Values( + (DevNameTestParams){ + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=da6\n", + .is_disk = true, .devname = "da6"}, + (DevNameTestParams){.is_disk = false, .devname = "cuau0", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=cuau0\n"}, + (DevNameTestParams){.is_disk = true, .devname = "ada6", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=ada6\n"}, + (DevNameTestParams){.is_disk = true, .devname = "da6p1", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=da6p1\n"}, + (DevNameTestParams){.is_disk = true, .devname = "ada6p1", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=ada6p1\n"}, + (DevNameTestParams){.is_disk = true, .devname = "da6s0p1", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=da6s0p1\n"}, + (DevNameTestParams){.is_disk = true, .devname = "ada6s0p1", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=ada6s0p1\n"}, + /* + * Test physical path nodes. These are currently all set to false since + * physical path nodes are implemented with symlinks, and most CAM and + * ZFS operations can't use symlinked device nodes + */ + /* A SpectraBSD-style physical path node*/ + (DevNameTestParams){.is_disk = false, .devname = "enc@50030480019f53fd/elmtype@array_device/slot@18/da", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=enc@50030480019f53fd/elmtype@array_device/slot@18/da\n"}, + (DevNameTestParams){.is_disk = false, .devname = "enc@50030480019f53fd/elmtype@array_device/slot@18/pass", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=enc@50030480019f53fd/elmtype@array_device/slot@18/pass\n"}, + /* A FreeBSD-style physical path node */ + (DevNameTestParams){.is_disk = true, .devname = "enc@n50030480019f53fd/type@0/slot@18/elmdesc@ArrayDevice18/da6", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=enc@n50030480019f53fd/type@0/slot@18/elmdesc@ArrayDevice18/da6\n"}, + (DevNameTestParams){.is_disk = false, .devname = "enc@n50030480019f53fd/type@0/slot@18/elmdesc@ArrayDevice18/pass6", + .evs = "!system=DEVFS subsystem=CDEV type=CREATE cdev=enc@n50030480019f53fd/type@0/slot@18/elmdesc@ArrayDevice18/pass6\n"}, + + /* + * Test some GEOM events + */ + (DevNameTestParams){.is_disk = true, .devname = "da5", + .evs = "!system=GEOM subsystem=disk type=GEOM::physpath devname=da5\n"}) +); |