xref: /freebsd/lib/libdevdctl/event.cc (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
17a0c41d5SAlan Somers /*-
27a0c41d5SAlan Somers  * Copyright (c) 2011, 2012, 2013, 2016 Spectra Logic Corporation
37a0c41d5SAlan Somers  * All rights reserved.
47a0c41d5SAlan Somers  *
57a0c41d5SAlan Somers  * Redistribution and use in source and binary forms, with or without
67a0c41d5SAlan Somers  * modification, are permitted provided that the following conditions
77a0c41d5SAlan Somers  * are met:
87a0c41d5SAlan Somers  * 1. Redistributions of source code must retain the above copyright
97a0c41d5SAlan Somers  *    notice, this list of conditions, and the following disclaimer,
107a0c41d5SAlan Somers  *    without modification.
117a0c41d5SAlan Somers  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
127a0c41d5SAlan Somers  *    substantially similar to the "NO WARRANTY" disclaimer below
137a0c41d5SAlan Somers  *    ("Disclaimer") and any redistribution must be conditioned upon
147a0c41d5SAlan Somers  *    including a substantially similar Disclaimer requirement for further
157a0c41d5SAlan Somers  *    binary redistribution.
167a0c41d5SAlan Somers  *
177a0c41d5SAlan Somers  * NO WARRANTY
187a0c41d5SAlan Somers  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
197a0c41d5SAlan Somers  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
207a0c41d5SAlan Somers  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
217a0c41d5SAlan Somers  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
227a0c41d5SAlan Somers  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237a0c41d5SAlan Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247a0c41d5SAlan Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257a0c41d5SAlan Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
267a0c41d5SAlan Somers  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
277a0c41d5SAlan Somers  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
287a0c41d5SAlan Somers  * POSSIBILITY OF SUCH DAMAGES.
297a0c41d5SAlan Somers  *
307a0c41d5SAlan Somers  * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
317a0c41d5SAlan Somers  */
327a0c41d5SAlan Somers 
337a0c41d5SAlan Somers /**
347a0c41d5SAlan Somers  * \file event.cc
357a0c41d5SAlan Somers  *
367a0c41d5SAlan Somers  * Implementation of the class hierarchy used to express events
377a0c41d5SAlan Somers  * received via the devdctl API.
387a0c41d5SAlan Somers  */
397a0c41d5SAlan Somers #include <sys/cdefs.h>
407a0c41d5SAlan Somers #include <sys/disk.h>
417a0c41d5SAlan Somers #include <sys/filio.h>
427a0c41d5SAlan Somers #include <sys/param.h>
437a0c41d5SAlan Somers #include <sys/stat.h>
447a0c41d5SAlan Somers 
457a0c41d5SAlan Somers #include <err.h>
467a0c41d5SAlan Somers #include <fcntl.h>
477a0c41d5SAlan Somers #include <inttypes.h>
487a0c41d5SAlan Somers #include <paths.h>
497a0c41d5SAlan Somers #include <stdlib.h>
507a0c41d5SAlan Somers #include <syslog.h>
517a0c41d5SAlan Somers #include <unistd.h>
527a0c41d5SAlan Somers 
537a0c41d5SAlan Somers #include <cstdarg>
547a0c41d5SAlan Somers #include <cstring>
557a0c41d5SAlan Somers #include <iostream>
567a0c41d5SAlan Somers #include <list>
577a0c41d5SAlan Somers #include <map>
587a0c41d5SAlan Somers #include <sstream>
597a0c41d5SAlan Somers #include <string>
607a0c41d5SAlan Somers 
617a0c41d5SAlan Somers #include "guid.h"
627a0c41d5SAlan Somers #include "event.h"
637a0c41d5SAlan Somers #include "event_factory.h"
647a0c41d5SAlan Somers #include "exception.h"
657a0c41d5SAlan Somers /*================================== Macros ==================================*/
667a0c41d5SAlan Somers #define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))
677a0c41d5SAlan Somers 
687a0c41d5SAlan Somers /*============================ Namespace Control =============================*/
697a0c41d5SAlan Somers using std::cout;
707a0c41d5SAlan Somers using std::endl;
717a0c41d5SAlan Somers using std::string;
727a0c41d5SAlan Somers using std::stringstream;
737a0c41d5SAlan Somers 
747a0c41d5SAlan Somers namespace DevdCtl
757a0c41d5SAlan Somers {
767a0c41d5SAlan Somers 
777a0c41d5SAlan Somers /*=========================== Class Implementations ==========================*/
787a0c41d5SAlan Somers /*----------------------------------- Event ----------------------------------*/
797a0c41d5SAlan Somers //- Event Static Protected Data ------------------------------------------------
807a0c41d5SAlan Somers const string Event::s_theEmptyString;
817a0c41d5SAlan Somers 
827a0c41d5SAlan Somers Event::EventTypeRecord Event::s_typeTable[] =
837a0c41d5SAlan Somers {
847a0c41d5SAlan Somers 	{ Event::NOTIFY,  "Notify" },
857a0c41d5SAlan Somers 	{ Event::NOMATCH, "No Driver Match" },
867a0c41d5SAlan Somers 	{ Event::ATTACH,  "Attach" },
877a0c41d5SAlan Somers 	{ Event::DETACH,  "Detach" }
887a0c41d5SAlan Somers };
897a0c41d5SAlan Somers 
907a0c41d5SAlan Somers //- Event Static Public Methods ------------------------------------------------
917a0c41d5SAlan Somers Event *
Builder(Event::Type type,NVPairMap & nvPairs,const string & eventString)927a0c41d5SAlan Somers Event::Builder(Event::Type type, NVPairMap &nvPairs,
937a0c41d5SAlan Somers 	       const string &eventString)
947a0c41d5SAlan Somers {
957a0c41d5SAlan Somers 	return (new Event(type, nvPairs, eventString));
967a0c41d5SAlan Somers }
977a0c41d5SAlan Somers 
987a0c41d5SAlan Somers Event *
CreateEvent(const EventFactory & factory,const string & eventString)997a0c41d5SAlan Somers Event::CreateEvent(const EventFactory &factory, const string &eventString)
1007a0c41d5SAlan Somers {
1017a0c41d5SAlan Somers 	NVPairMap &nvpairs(*new NVPairMap);
1027a0c41d5SAlan Somers 	Type       type(static_cast<Event::Type>(eventString[0]));
1037a0c41d5SAlan Somers 
1047a0c41d5SAlan Somers 	try {
1057a0c41d5SAlan Somers 		ParseEventString(type, eventString, nvpairs);
1067a0c41d5SAlan Somers 	} catch (const ParseException &exp) {
1077a0c41d5SAlan Somers 		if (exp.GetType() == ParseException::INVALID_FORMAT)
1087a0c41d5SAlan Somers 			exp.Log();
1097a0c41d5SAlan Somers 		return (NULL);
1107a0c41d5SAlan Somers 	}
1117a0c41d5SAlan Somers 
1127a0c41d5SAlan Somers 	/*
1137a0c41d5SAlan Somers 	 * Allow entries in our table for events with no system specified.
1147a0c41d5SAlan Somers 	 * These entries should specify the string "none".
1157a0c41d5SAlan Somers 	 */
1167a0c41d5SAlan Somers 	NVPairMap::iterator system_item(nvpairs.find("system"));
1177a0c41d5SAlan Somers 	if (system_item == nvpairs.end())
1187a0c41d5SAlan Somers 		nvpairs["system"] = "none";
1197a0c41d5SAlan Somers 
1207a0c41d5SAlan Somers 	return (factory.Build(type, nvpairs, eventString));
1217a0c41d5SAlan Somers }
1227a0c41d5SAlan Somers 
1237a0c41d5SAlan Somers bool
DevName(std::string & name) const1247a0c41d5SAlan Somers Event::DevName(std::string &name) const
1257a0c41d5SAlan Somers {
1267a0c41d5SAlan Somers 	return (false);
1277a0c41d5SAlan Somers }
1287a0c41d5SAlan Somers 
1297a0c41d5SAlan Somers /* TODO: simplify this function with C++-11 <regex> methods */
1307a0c41d5SAlan Somers bool
IsDiskDev() const1317a0c41d5SAlan Somers Event::IsDiskDev() const
1327a0c41d5SAlan Somers {
1337a0c41d5SAlan Somers 	const int numDrivers = 2;
1347a0c41d5SAlan Somers 	static const char *diskDevNames[numDrivers] =
1357a0c41d5SAlan Somers 	{
1367a0c41d5SAlan Somers 		"da",
1377a0c41d5SAlan Somers 		"ada"
1387a0c41d5SAlan Somers 	};
1397a0c41d5SAlan Somers 	const char **dName;
1407a0c41d5SAlan Somers 	string devName;
1417a0c41d5SAlan Somers 
1427a0c41d5SAlan Somers 	if (! DevName(devName))
1437a0c41d5SAlan Somers 		return false;
1447a0c41d5SAlan Somers 
1457a0c41d5SAlan Somers 	size_t find_start = devName.rfind('/');
1467a0c41d5SAlan Somers 	if (find_start == string::npos) {
1477a0c41d5SAlan Somers 		find_start = 0;
1487a0c41d5SAlan Somers 	} else {
1497a0c41d5SAlan Somers 		/* Just after the last '/'. */
1507a0c41d5SAlan Somers 		find_start++;
1517a0c41d5SAlan Somers 	}
1527a0c41d5SAlan Somers 
1537a0c41d5SAlan Somers 	for (dName = &diskDevNames[0];
1547a0c41d5SAlan Somers 	     dName <= &diskDevNames[numDrivers - 1]; dName++) {
1557a0c41d5SAlan Somers 
1567a0c41d5SAlan Somers 		size_t loc(devName.find(*dName, find_start));
1577a0c41d5SAlan Somers 		if (loc == find_start) {
1587a0c41d5SAlan Somers 			size_t prefixLen(strlen(*dName));
1597a0c41d5SAlan Somers 
1607a0c41d5SAlan Somers 			if (devName.length() - find_start >= prefixLen
1617a0c41d5SAlan Somers 			 && isdigit(devName[find_start + prefixLen]))
1627a0c41d5SAlan Somers 				return (true);
1637a0c41d5SAlan Somers 		}
1647a0c41d5SAlan Somers 	}
1657a0c41d5SAlan Somers 
1667a0c41d5SAlan Somers 	return (false);
1677a0c41d5SAlan Somers }
1687a0c41d5SAlan Somers 
1697a0c41d5SAlan Somers const char *
TypeToString(Event::Type type)1707a0c41d5SAlan Somers Event::TypeToString(Event::Type type)
1717a0c41d5SAlan Somers {
1727a0c41d5SAlan Somers 	EventTypeRecord *rec(s_typeTable);
1737a0c41d5SAlan Somers 	EventTypeRecord *lastRec(s_typeTable + NUM_ELEMENTS(s_typeTable) - 1);
1747a0c41d5SAlan Somers 
1757a0c41d5SAlan Somers 	for (; rec <= lastRec; rec++) {
1767a0c41d5SAlan Somers 		if (rec->m_type == type)
1777a0c41d5SAlan Somers 			return (rec->m_typeName);
1787a0c41d5SAlan Somers 	}
1797a0c41d5SAlan Somers 	return ("Unknown");
1807a0c41d5SAlan Somers }
1817a0c41d5SAlan Somers 
1827a0c41d5SAlan Somers //- Event Public Methods -------------------------------------------------------
1837a0c41d5SAlan Somers const string &
Value(const string & varName) const1847a0c41d5SAlan Somers Event::Value(const string &varName) const
1857a0c41d5SAlan Somers {
1867a0c41d5SAlan Somers 	NVPairMap::const_iterator item(m_nvPairs.find(varName));
1877a0c41d5SAlan Somers 	if (item == m_nvPairs.end())
1887a0c41d5SAlan Somers 		return (s_theEmptyString);
1897a0c41d5SAlan Somers 
1907a0c41d5SAlan Somers 	return (item->second);
1917a0c41d5SAlan Somers }
1927a0c41d5SAlan Somers 
1937a0c41d5SAlan Somers bool
Contains(const string & varName) const1947a0c41d5SAlan Somers Event::Contains(const string &varName) const
1957a0c41d5SAlan Somers {
1967a0c41d5SAlan Somers 	return (m_nvPairs.find(varName) != m_nvPairs.end());
1977a0c41d5SAlan Somers }
1987a0c41d5SAlan Somers 
1997a0c41d5SAlan Somers string
ToString() const2007a0c41d5SAlan Somers Event::ToString() const
2017a0c41d5SAlan Somers {
2027a0c41d5SAlan Somers 	stringstream result;
2037a0c41d5SAlan Somers 
2047a0c41d5SAlan Somers 	NVPairMap::const_iterator devName(m_nvPairs.find("device-name"));
2057a0c41d5SAlan Somers 	if (devName != m_nvPairs.end())
2067a0c41d5SAlan Somers 		result << devName->second << ": ";
2077a0c41d5SAlan Somers 
2087a0c41d5SAlan Somers 	NVPairMap::const_iterator systemName(m_nvPairs.find("system"));
2097a0c41d5SAlan Somers 	if (systemName != m_nvPairs.end()
2107a0c41d5SAlan Somers 	 && systemName->second != "none")
2117a0c41d5SAlan Somers 		result << systemName->second << ": ";
2127a0c41d5SAlan Somers 
2137a0c41d5SAlan Somers 	result << TypeToString(GetType()) << ' ';
2147a0c41d5SAlan Somers 
2157a0c41d5SAlan Somers 	for (NVPairMap::const_iterator curVar = m_nvPairs.begin();
2167a0c41d5SAlan Somers 	     curVar != m_nvPairs.end(); curVar++) {
2177a0c41d5SAlan Somers 		if (curVar == devName || curVar == systemName)
2187a0c41d5SAlan Somers 			continue;
2197a0c41d5SAlan Somers 
2207a0c41d5SAlan Somers 		result << ' '
2217a0c41d5SAlan Somers 		     << curVar->first << "=" << curVar->second;
2227a0c41d5SAlan Somers 	}
2237a0c41d5SAlan Somers 	result << endl;
2247a0c41d5SAlan Somers 
2257a0c41d5SAlan Somers 	return (result.str());
2267a0c41d5SAlan Somers }
2277a0c41d5SAlan Somers 
2287a0c41d5SAlan Somers void
Print() const2297a0c41d5SAlan Somers Event::Print() const
2307a0c41d5SAlan Somers {
2317a0c41d5SAlan Somers 	cout << ToString() << std::flush;
2327a0c41d5SAlan Somers }
2337a0c41d5SAlan Somers 
2347a0c41d5SAlan Somers void
Log(int priority) const2357a0c41d5SAlan Somers Event::Log(int priority) const
2367a0c41d5SAlan Somers {
2377a0c41d5SAlan Somers 	syslog(priority, "%s", ToString().c_str());
2387a0c41d5SAlan Somers }
2397a0c41d5SAlan Somers 
2407a0c41d5SAlan Somers //- Event Virtual Public Methods -----------------------------------------------
~Event()2417a0c41d5SAlan Somers Event::~Event()
2427a0c41d5SAlan Somers {
2437a0c41d5SAlan Somers 	delete &m_nvPairs;
2447a0c41d5SAlan Somers }
2457a0c41d5SAlan Somers 
2467a0c41d5SAlan Somers Event *
DeepCopy() const2477a0c41d5SAlan Somers Event::DeepCopy() const
2487a0c41d5SAlan Somers {
2497a0c41d5SAlan Somers 	return (new Event(*this));
2507a0c41d5SAlan Somers }
2517a0c41d5SAlan Somers 
2527a0c41d5SAlan Somers bool
Process() const2537a0c41d5SAlan Somers Event::Process() const
2547a0c41d5SAlan Somers {
2557a0c41d5SAlan Somers 	return (false);
2567a0c41d5SAlan Somers }
2577a0c41d5SAlan Somers 
2587a0c41d5SAlan Somers timeval
GetTimestamp() const2597a0c41d5SAlan Somers Event::GetTimestamp() const
2607a0c41d5SAlan Somers {
2617a0c41d5SAlan Somers 	timeval tv_timestamp;
2627a0c41d5SAlan Somers 	struct tm tm_timestamp;
2637a0c41d5SAlan Somers 
2647a0c41d5SAlan Somers 	if (!Contains("timestamp")) {
2657a0c41d5SAlan Somers 		throw Exception("Event contains no timestamp: %s",
2667a0c41d5SAlan Somers 				m_eventString.c_str());
2677a0c41d5SAlan Somers 	}
2687a0c41d5SAlan Somers 	strptime(Value(string("timestamp")).c_str(), "%s", &tm_timestamp);
2697a0c41d5SAlan Somers 	tv_timestamp.tv_sec = mktime(&tm_timestamp);
2707a0c41d5SAlan Somers 	tv_timestamp.tv_usec = 0;
2717a0c41d5SAlan Somers 	return (tv_timestamp);
2727a0c41d5SAlan Somers }
2737a0c41d5SAlan Somers 
2747a0c41d5SAlan Somers bool
DevPath(std::string & path) const2757a0c41d5SAlan Somers Event::DevPath(std::string &path) const
2767a0c41d5SAlan Somers {
277*e49d3eb4SAlexander Motin 	char buf[SPECNAMELEN + 1];
2787a0c41d5SAlan Somers 	string devName;
2797a0c41d5SAlan Somers 
2807a0c41d5SAlan Somers 	if (!DevName(devName))
2817a0c41d5SAlan Somers 		return (false);
2827a0c41d5SAlan Somers 
2837a0c41d5SAlan Somers 	string devPath(_PATH_DEV + devName);
2847a0c41d5SAlan Somers 	int devFd(open(devPath.c_str(), O_RDONLY));
2857a0c41d5SAlan Somers 	if (devFd == -1)
2867a0c41d5SAlan Somers 		return (false);
2877a0c41d5SAlan Somers 
2887a0c41d5SAlan Somers 	/* Normalize the device name in case the DEVFS event is for a link. */
289*e49d3eb4SAlexander Motin 	if (fdevname_r(devFd, buf, sizeof(buf)) == NULL) {
290*e49d3eb4SAlexander Motin 		close(devFd);
291*e49d3eb4SAlexander Motin 		return (false);
292*e49d3eb4SAlexander Motin 	}
293*e49d3eb4SAlexander Motin 	devName = buf;
2947a0c41d5SAlan Somers 	path = _PATH_DEV + devName;
2957a0c41d5SAlan Somers 
2967a0c41d5SAlan Somers 	close(devFd);
2977a0c41d5SAlan Somers 
2987a0c41d5SAlan Somers 	return (true);
2997a0c41d5SAlan Somers }
3007a0c41d5SAlan Somers 
3017a0c41d5SAlan Somers bool
PhysicalPath(std::string & path) const3027a0c41d5SAlan Somers Event::PhysicalPath(std::string &path) const
3037a0c41d5SAlan Somers {
3047a0c41d5SAlan Somers 	string devPath;
3057a0c41d5SAlan Somers 
3067a0c41d5SAlan Somers 	if (!DevPath(devPath))
3077a0c41d5SAlan Somers 		return (false);
3087a0c41d5SAlan Somers 
3097a0c41d5SAlan Somers 	int devFd(open(devPath.c_str(), O_RDONLY));
3107a0c41d5SAlan Somers 	if (devFd == -1)
3117a0c41d5SAlan Somers 		return (false);
3127a0c41d5SAlan Somers 
3137a0c41d5SAlan Somers 	char physPath[MAXPATHLEN];
3147a0c41d5SAlan Somers 	physPath[0] = '\0';
3157a0c41d5SAlan Somers 	bool result(ioctl(devFd, DIOCGPHYSPATH, physPath) == 0);
3167a0c41d5SAlan Somers 	close(devFd);
3177a0c41d5SAlan Somers 	if (result)
3187a0c41d5SAlan Somers 		path = physPath;
3197a0c41d5SAlan Somers 	return (result);
3207a0c41d5SAlan Somers }
3217a0c41d5SAlan Somers 
3227a0c41d5SAlan Somers //- Event Protected Methods ----------------------------------------------------
Event(Type type,NVPairMap & map,const string & eventString)3237a0c41d5SAlan Somers Event::Event(Type type, NVPairMap &map, const string &eventString)
3247a0c41d5SAlan Somers  : m_type(type),
3257a0c41d5SAlan Somers    m_nvPairs(map),
3267a0c41d5SAlan Somers    m_eventString(eventString)
3277a0c41d5SAlan Somers {
3287a0c41d5SAlan Somers }
3297a0c41d5SAlan Somers 
Event(const Event & src)3307a0c41d5SAlan Somers Event::Event(const Event &src)
3317a0c41d5SAlan Somers  : m_type(src.m_type),
3327a0c41d5SAlan Somers    m_nvPairs(*new NVPairMap(src.m_nvPairs)),
3337a0c41d5SAlan Somers    m_eventString(src.m_eventString)
3347a0c41d5SAlan Somers {
3357a0c41d5SAlan Somers }
3367a0c41d5SAlan Somers 
3377a0c41d5SAlan Somers void
ParseEventString(Event::Type type,const string & eventString,NVPairMap & nvpairs)3387a0c41d5SAlan Somers Event::ParseEventString(Event::Type type,
3397a0c41d5SAlan Somers 			      const string &eventString,
3407a0c41d5SAlan Somers 			      NVPairMap& nvpairs)
3417a0c41d5SAlan Somers {
3427a0c41d5SAlan Somers 	size_t start;
3437a0c41d5SAlan Somers 	size_t end;
3447a0c41d5SAlan Somers 
3457a0c41d5SAlan Somers 	switch (type) {
3467a0c41d5SAlan Somers 	case ATTACH:
3477a0c41d5SAlan Somers 	case DETACH:
3487a0c41d5SAlan Somers 
3497a0c41d5SAlan Somers 		/*
3507a0c41d5SAlan Somers 		 * <type><device-name><unit> <pnpvars> \
3517a0c41d5SAlan Somers 		 *                        at <location vars> <pnpvars> \
3527a0c41d5SAlan Somers 		 *                        on <parent>
3537a0c41d5SAlan Somers 		 *
3547a0c41d5SAlan Somers 		 * Handle all data that doesn't conform to the
3557a0c41d5SAlan Somers 		 * "name=value" format, and let the generic parser
3567a0c41d5SAlan Somers 		 * below handle the rest.
3577a0c41d5SAlan Somers 		 *
3587a0c41d5SAlan Somers 		 * Type is a single char.  Skip it.
3597a0c41d5SAlan Somers 		 */
3607a0c41d5SAlan Somers 		start = 1;
3617a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
3627a0c41d5SAlan Somers 		if (end == string::npos)
3637a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
3647a0c41d5SAlan Somers 					     eventString, start);
3657a0c41d5SAlan Somers 
3667a0c41d5SAlan Somers 		nvpairs["device-name"] = eventString.substr(start, end - start);
3677a0c41d5SAlan Somers 
3687a0c41d5SAlan Somers 		start = eventString.find(" on ", end);
3697a0c41d5SAlan Somers 		if (end == string::npos)
3707a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
3717a0c41d5SAlan Somers 					     eventString, start);
3727a0c41d5SAlan Somers 		start += 4;
3737a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
3747a0c41d5SAlan Somers 		nvpairs["parent"] = eventString.substr(start, end);
3757a0c41d5SAlan Somers 		break;
3767a0c41d5SAlan Somers 	case NOTIFY:
3777a0c41d5SAlan Somers 		break;
3787a0c41d5SAlan Somers 	case NOMATCH:
3797a0c41d5SAlan Somers 		throw ParseException(ParseException::DISCARDED_EVENT_TYPE,
3807a0c41d5SAlan Somers 				     eventString);
3817a0c41d5SAlan Somers 	default:
3827a0c41d5SAlan Somers 		throw ParseException(ParseException::UNKNOWN_EVENT_TYPE,
3837a0c41d5SAlan Somers 				     eventString);
3847a0c41d5SAlan Somers 	}
3857a0c41d5SAlan Somers 
3867a0c41d5SAlan Somers 	/* Process common "key=value" format. */
3877a0c41d5SAlan Somers 	for (start = 1; start < eventString.length(); start = end + 1) {
3887a0c41d5SAlan Somers 
3897a0c41d5SAlan Somers 		/* Find the '=' in the middle of the key/value pair. */
3907a0c41d5SAlan Somers 		end = eventString.find('=', start);
3917a0c41d5SAlan Somers 		if (end == string::npos)
3927a0c41d5SAlan Somers 			break;
3937a0c41d5SAlan Somers 
3947a0c41d5SAlan Somers 		/*
3957a0c41d5SAlan Somers 		 * Find the start of the key by backing up until
3967a0c41d5SAlan Somers 		 * we hit whitespace or '!' (event type "notice").
3977a0c41d5SAlan Somers 		 * Due to the devdctl format, all key/value pair must
3987a0c41d5SAlan Somers 		 * start with one of these two characters.
3997a0c41d5SAlan Somers 		 */
4007a0c41d5SAlan Somers 		start = eventString.find_last_of("! \t\n", end);
4017a0c41d5SAlan Somers 		if (start == string::npos)
4027a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
4037a0c41d5SAlan Somers 					     eventString, end);
4047a0c41d5SAlan Somers 		start++;
4057a0c41d5SAlan Somers 		string key(eventString.substr(start, end - start));
4067a0c41d5SAlan Somers 
4077a0c41d5SAlan Somers 		/*
4087a0c41d5SAlan Somers 		 * Walk forward from the '=' until either we exhaust
4097a0c41d5SAlan Somers 		 * the buffer or we hit whitespace.
4107a0c41d5SAlan Somers 		 */
4117a0c41d5SAlan Somers 		start = end + 1;
4127a0c41d5SAlan Somers 		if (start >= eventString.length())
4137a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
4147a0c41d5SAlan Somers 					     eventString, end);
4157a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
4167a0c41d5SAlan Somers 		if (end == string::npos)
4177a0c41d5SAlan Somers 			end = eventString.length() - 1;
4187a0c41d5SAlan Somers 		string value(eventString.substr(start, end - start));
4197a0c41d5SAlan Somers 
4207a0c41d5SAlan Somers 		nvpairs[key] = value;
4217a0c41d5SAlan Somers 	}
4227a0c41d5SAlan Somers }
4237a0c41d5SAlan Somers 
4247a0c41d5SAlan Somers void
TimestampEventString(std::string & eventString)4257a0c41d5SAlan Somers Event::TimestampEventString(std::string &eventString)
4267a0c41d5SAlan Somers {
4277a0c41d5SAlan Somers 	if (eventString.size() > 0) {
4287a0c41d5SAlan Somers 		/*
4297a0c41d5SAlan Somers 		 * Add a timestamp as the final field of the event if it is
4307a0c41d5SAlan Somers 		 * not already present.
4317a0c41d5SAlan Somers 		 */
4327a0c41d5SAlan Somers 		if (eventString.find(" timestamp=") == string::npos) {
4337a0c41d5SAlan Somers 			const size_t bufsize = 32;	// Long enough for a 64-bit int
4347a0c41d5SAlan Somers 			timeval now;
4357a0c41d5SAlan Somers 			char timebuf[bufsize];
4367a0c41d5SAlan Somers 
4377a0c41d5SAlan Somers 			size_t eventEnd(eventString.find_last_not_of('\n') + 1);
4387a0c41d5SAlan Somers 			if (gettimeofday(&now, NULL) != 0)
4397a0c41d5SAlan Somers 				err(1, "gettimeofday");
4407a0c41d5SAlan Somers 			snprintf(timebuf, bufsize, " timestamp=%" PRId64,
4417a0c41d5SAlan Somers 				(int64_t) now.tv_sec);
4427a0c41d5SAlan Somers 			eventString.insert(eventEnd, timebuf);
4437a0c41d5SAlan Somers 		}
4447a0c41d5SAlan Somers 	}
4457a0c41d5SAlan Somers }
4467a0c41d5SAlan Somers 
4477a0c41d5SAlan Somers /*-------------------------------- DevfsEvent --------------------------------*/
4487a0c41d5SAlan Somers //- DevfsEvent Static Public Methods -------------------------------------------
4497a0c41d5SAlan Somers Event *
Builder(Event::Type type,NVPairMap & nvPairs,const string & eventString)4507a0c41d5SAlan Somers DevfsEvent::Builder(Event::Type type, NVPairMap &nvPairs,
4517a0c41d5SAlan Somers 		    const string &eventString)
4527a0c41d5SAlan Somers {
4537a0c41d5SAlan Somers 	return (new DevfsEvent(type, nvPairs, eventString));
4547a0c41d5SAlan Somers }
4557a0c41d5SAlan Somers 
4567a0c41d5SAlan Somers //- DevfsEvent Static Protected Methods ----------------------------------------
4577a0c41d5SAlan Somers bool
IsWholeDev(const string & devName)4587a0c41d5SAlan Somers DevfsEvent::IsWholeDev(const string &devName)
4597a0c41d5SAlan Somers {
4607a0c41d5SAlan Somers 	string::const_iterator i(devName.begin());
4617a0c41d5SAlan Somers 
4627a0c41d5SAlan Somers 	size_t start = devName.rfind('/');
4637a0c41d5SAlan Somers 	if (start == string::npos) {
4647a0c41d5SAlan Somers 		start = 0;
4657a0c41d5SAlan Somers 	} else {
4667a0c41d5SAlan Somers 		/* Just after the last '/'. */
4677a0c41d5SAlan Somers 		start++;
4687a0c41d5SAlan Somers 	}
4697a0c41d5SAlan Somers 	i += start;
4707a0c41d5SAlan Somers 
4717a0c41d5SAlan Somers 	/* alpha prefix followed only by digits. */
4727a0c41d5SAlan Somers 	for (; i < devName.end() && !isdigit(*i); i++)
4737a0c41d5SAlan Somers 		;
4747a0c41d5SAlan Somers 
4757a0c41d5SAlan Somers 	if (i == devName.end())
4767a0c41d5SAlan Somers 		return (false);
4777a0c41d5SAlan Somers 
4787a0c41d5SAlan Somers 	for (; i < devName.end() && isdigit(*i); i++)
4797a0c41d5SAlan Somers 		;
4807a0c41d5SAlan Somers 
4817a0c41d5SAlan Somers 	return (i == devName.end());
4827a0c41d5SAlan Somers }
4837a0c41d5SAlan Somers 
4847a0c41d5SAlan Somers //- DevfsEvent Virtual Public Methods ------------------------------------------
4857a0c41d5SAlan Somers Event *
DeepCopy() const4867a0c41d5SAlan Somers DevfsEvent::DeepCopy() const
4877a0c41d5SAlan Somers {
4887a0c41d5SAlan Somers 	return (new DevfsEvent(*this));
4897a0c41d5SAlan Somers }
4907a0c41d5SAlan Somers 
4917a0c41d5SAlan Somers bool
Process() const4927a0c41d5SAlan Somers DevfsEvent::Process() const
4937a0c41d5SAlan Somers {
4947a0c41d5SAlan Somers 	return (true);
4957a0c41d5SAlan Somers }
4967a0c41d5SAlan Somers 
4977a0c41d5SAlan Somers //- DevfsEvent Public Methods --------------------------------------------------
4987a0c41d5SAlan Somers bool
IsWholeDev() const4997a0c41d5SAlan Somers DevfsEvent::IsWholeDev() const
5007a0c41d5SAlan Somers {
5017a0c41d5SAlan Somers 	string devName;
5027a0c41d5SAlan Somers 
5037a0c41d5SAlan Somers 	return (DevName(devName) && IsDiskDev() && IsWholeDev(devName));
5047a0c41d5SAlan Somers }
5057a0c41d5SAlan Somers 
5067a0c41d5SAlan Somers bool
DevName(std::string & name) const5077a0c41d5SAlan Somers DevfsEvent::DevName(std::string &name) const
5087a0c41d5SAlan Somers {
5097a0c41d5SAlan Somers 	if (Value("subsystem") != "CDEV")
5107a0c41d5SAlan Somers 		return (false);
5117a0c41d5SAlan Somers 
5127a0c41d5SAlan Somers 	name = Value("cdev");
5137a0c41d5SAlan Somers 	return (!name.empty());
5147a0c41d5SAlan Somers }
5157a0c41d5SAlan Somers 
5167a0c41d5SAlan Somers //- DevfsEvent Protected Methods -----------------------------------------------
DevfsEvent(Event::Type type,NVPairMap & nvpairs,const string & eventString)5177a0c41d5SAlan Somers DevfsEvent::DevfsEvent(Event::Type type, NVPairMap &nvpairs,
5187a0c41d5SAlan Somers 		       const string &eventString)
5197a0c41d5SAlan Somers  : Event(type, nvpairs, eventString)
5207a0c41d5SAlan Somers {
5217a0c41d5SAlan Somers }
5227a0c41d5SAlan Somers 
DevfsEvent(const DevfsEvent & src)5237a0c41d5SAlan Somers DevfsEvent::DevfsEvent(const DevfsEvent &src)
5247a0c41d5SAlan Somers  : Event(src)
5257a0c41d5SAlan Somers {
5267a0c41d5SAlan Somers }
5277a0c41d5SAlan Somers 
5287a0c41d5SAlan Somers /*--------------------------------- GeomEvent --------------------------------*/
5297a0c41d5SAlan Somers //- GeomEvent Static Public Methods --------------------------------------------
5307a0c41d5SAlan Somers Event *
Builder(Event::Type type,NVPairMap & nvpairs,const string & eventString)5317a0c41d5SAlan Somers GeomEvent::Builder(Event::Type type, NVPairMap &nvpairs,
5327a0c41d5SAlan Somers 		   const string &eventString)
5337a0c41d5SAlan Somers {
5347a0c41d5SAlan Somers 	return (new GeomEvent(type, nvpairs, eventString));
5357a0c41d5SAlan Somers }
5367a0c41d5SAlan Somers 
5377a0c41d5SAlan Somers //- GeomEvent Virtual Public Methods -------------------------------------------
5387a0c41d5SAlan Somers Event *
DeepCopy() const5397a0c41d5SAlan Somers GeomEvent::DeepCopy() const
5407a0c41d5SAlan Somers {
5417a0c41d5SAlan Somers 	return (new GeomEvent(*this));
5427a0c41d5SAlan Somers }
5437a0c41d5SAlan Somers 
5447a0c41d5SAlan Somers bool
DevName(std::string & name) const5457a0c41d5SAlan Somers GeomEvent::DevName(std::string &name) const
5467a0c41d5SAlan Somers {
547a07d59d1SAlan Somers 	if (Value("subsystem") == "disk")
5487a0c41d5SAlan Somers 		name = Value("devname");
549a07d59d1SAlan Somers 	else
550a07d59d1SAlan Somers 		name = Value("cdev");
5517a0c41d5SAlan Somers 	return (!name.empty());
5527a0c41d5SAlan Somers }
5537a0c41d5SAlan Somers 
5547a0c41d5SAlan Somers 
5557a0c41d5SAlan Somers //- GeomEvent Protected Methods ------------------------------------------------
GeomEvent(Event::Type type,NVPairMap & nvpairs,const string & eventString)5567a0c41d5SAlan Somers GeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs,
5577a0c41d5SAlan Somers 		     const string &eventString)
5587a0c41d5SAlan Somers  : Event(type, nvpairs, eventString),
5597a0c41d5SAlan Somers    m_devname(Value("devname"))
5607a0c41d5SAlan Somers {
5617a0c41d5SAlan Somers }
5627a0c41d5SAlan Somers 
GeomEvent(const GeomEvent & src)5637a0c41d5SAlan Somers GeomEvent::GeomEvent(const GeomEvent &src)
5647a0c41d5SAlan Somers  : Event(src),
5657a0c41d5SAlan Somers    m_devname(src.m_devname)
5667a0c41d5SAlan Somers {
5677a0c41d5SAlan Somers }
5687a0c41d5SAlan Somers 
5697a0c41d5SAlan Somers /*--------------------------------- ZfsEvent ---------------------------------*/
5707a0c41d5SAlan Somers //- ZfsEvent Static Public Methods ---------------------------------------------
5717a0c41d5SAlan Somers Event *
Builder(Event::Type type,NVPairMap & nvpairs,const string & eventString)5727a0c41d5SAlan Somers ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs,
5737a0c41d5SAlan Somers 		  const string &eventString)
5747a0c41d5SAlan Somers {
5757a0c41d5SAlan Somers 	return (new ZfsEvent(type, nvpairs, eventString));
5767a0c41d5SAlan Somers }
5777a0c41d5SAlan Somers 
5787a0c41d5SAlan Somers //- ZfsEvent Virtual Public Methods --------------------------------------------
5797a0c41d5SAlan Somers Event *
DeepCopy() const5807a0c41d5SAlan Somers ZfsEvent::DeepCopy() const
5817a0c41d5SAlan Somers {
5827a0c41d5SAlan Somers 	return (new ZfsEvent(*this));
5837a0c41d5SAlan Somers }
5847a0c41d5SAlan Somers 
5857a0c41d5SAlan Somers bool
DevName(std::string & name) const5867a0c41d5SAlan Somers ZfsEvent::DevName(std::string &name) const
5877a0c41d5SAlan Somers {
5887a0c41d5SAlan Somers 	return (false);
5897a0c41d5SAlan Somers }
5907a0c41d5SAlan Somers 
5917a0c41d5SAlan Somers //- ZfsEvent Protected Methods -------------------------------------------------
ZfsEvent(Event::Type type,NVPairMap & nvpairs,const string & eventString)5927a0c41d5SAlan Somers ZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs,
5937a0c41d5SAlan Somers 		   const string &eventString)
5947a0c41d5SAlan Somers  : Event(type, nvpairs, eventString),
5957a0c41d5SAlan Somers    m_poolGUID(Guid(Value("pool_guid"))),
5967a0c41d5SAlan Somers    m_vdevGUID(Guid(Value("vdev_guid")))
5977a0c41d5SAlan Somers {
5987a0c41d5SAlan Somers }
5997a0c41d5SAlan Somers 
ZfsEvent(const ZfsEvent & src)6007a0c41d5SAlan Somers ZfsEvent::ZfsEvent(const ZfsEvent &src)
6017a0c41d5SAlan Somers  : Event(src),
6027a0c41d5SAlan Somers    m_poolGUID(src.m_poolGUID),
6037a0c41d5SAlan Somers    m_vdevGUID(src.m_vdevGUID)
6047a0c41d5SAlan Somers {
6057a0c41d5SAlan Somers }
6067a0c41d5SAlan Somers 
6077a0c41d5SAlan Somers } // namespace DevdCtl
608