xref: /freebsd/lib/libdevdctl/event.cc (revision e49d3eb40324eaffaa13b93f2c4173dfa04dfa34)
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 
667a0c41d5SAlan Somers __FBSDID("$FreeBSD$");
677a0c41d5SAlan Somers 
687a0c41d5SAlan Somers /*================================== Macros ==================================*/
697a0c41d5SAlan Somers #define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))
707a0c41d5SAlan Somers 
717a0c41d5SAlan Somers /*============================ Namespace Control =============================*/
727a0c41d5SAlan Somers using std::cout;
737a0c41d5SAlan Somers using std::endl;
747a0c41d5SAlan Somers using std::string;
757a0c41d5SAlan Somers using std::stringstream;
767a0c41d5SAlan Somers 
777a0c41d5SAlan Somers namespace DevdCtl
787a0c41d5SAlan Somers {
797a0c41d5SAlan Somers 
807a0c41d5SAlan Somers /*=========================== Class Implementations ==========================*/
817a0c41d5SAlan Somers /*----------------------------------- Event ----------------------------------*/
827a0c41d5SAlan Somers //- Event Static Protected Data ------------------------------------------------
837a0c41d5SAlan Somers const string Event::s_theEmptyString;
847a0c41d5SAlan Somers 
857a0c41d5SAlan Somers Event::EventTypeRecord Event::s_typeTable[] =
867a0c41d5SAlan Somers {
877a0c41d5SAlan Somers 	{ Event::NOTIFY,  "Notify" },
887a0c41d5SAlan Somers 	{ Event::NOMATCH, "No Driver Match" },
897a0c41d5SAlan Somers 	{ Event::ATTACH,  "Attach" },
907a0c41d5SAlan Somers 	{ Event::DETACH,  "Detach" }
917a0c41d5SAlan Somers };
927a0c41d5SAlan Somers 
937a0c41d5SAlan Somers //- Event Static Public Methods ------------------------------------------------
947a0c41d5SAlan Somers Event *
957a0c41d5SAlan Somers Event::Builder(Event::Type type, NVPairMap &nvPairs,
967a0c41d5SAlan Somers 	       const string &eventString)
977a0c41d5SAlan Somers {
987a0c41d5SAlan Somers 	return (new Event(type, nvPairs, eventString));
997a0c41d5SAlan Somers }
1007a0c41d5SAlan Somers 
1017a0c41d5SAlan Somers Event *
1027a0c41d5SAlan Somers Event::CreateEvent(const EventFactory &factory, const string &eventString)
1037a0c41d5SAlan Somers {
1047a0c41d5SAlan Somers 	NVPairMap &nvpairs(*new NVPairMap);
1057a0c41d5SAlan Somers 	Type       type(static_cast<Event::Type>(eventString[0]));
1067a0c41d5SAlan Somers 
1077a0c41d5SAlan Somers 	try {
1087a0c41d5SAlan Somers 		ParseEventString(type, eventString, nvpairs);
1097a0c41d5SAlan Somers 	} catch (const ParseException &exp) {
1107a0c41d5SAlan Somers 		if (exp.GetType() == ParseException::INVALID_FORMAT)
1117a0c41d5SAlan Somers 			exp.Log();
1127a0c41d5SAlan Somers 		return (NULL);
1137a0c41d5SAlan Somers 	}
1147a0c41d5SAlan Somers 
1157a0c41d5SAlan Somers 	/*
1167a0c41d5SAlan Somers 	 * Allow entries in our table for events with no system specified.
1177a0c41d5SAlan Somers 	 * These entries should specify the string "none".
1187a0c41d5SAlan Somers 	 */
1197a0c41d5SAlan Somers 	NVPairMap::iterator system_item(nvpairs.find("system"));
1207a0c41d5SAlan Somers 	if (system_item == nvpairs.end())
1217a0c41d5SAlan Somers 		nvpairs["system"] = "none";
1227a0c41d5SAlan Somers 
1237a0c41d5SAlan Somers 	return (factory.Build(type, nvpairs, eventString));
1247a0c41d5SAlan Somers }
1257a0c41d5SAlan Somers 
1267a0c41d5SAlan Somers bool
1277a0c41d5SAlan Somers Event::DevName(std::string &name) const
1287a0c41d5SAlan Somers {
1297a0c41d5SAlan Somers 	return (false);
1307a0c41d5SAlan Somers }
1317a0c41d5SAlan Somers 
1327a0c41d5SAlan Somers /* TODO: simplify this function with C++-11 <regex> methods */
1337a0c41d5SAlan Somers bool
1347a0c41d5SAlan Somers Event::IsDiskDev() const
1357a0c41d5SAlan Somers {
1367a0c41d5SAlan Somers 	const int numDrivers = 2;
1377a0c41d5SAlan Somers 	static const char *diskDevNames[numDrivers] =
1387a0c41d5SAlan Somers 	{
1397a0c41d5SAlan Somers 		"da",
1407a0c41d5SAlan Somers 		"ada"
1417a0c41d5SAlan Somers 	};
1427a0c41d5SAlan Somers 	const char **dName;
1437a0c41d5SAlan Somers 	string devName;
1447a0c41d5SAlan Somers 
1457a0c41d5SAlan Somers 	if (! DevName(devName))
1467a0c41d5SAlan Somers 		return false;
1477a0c41d5SAlan Somers 
1487a0c41d5SAlan Somers 	size_t find_start = devName.rfind('/');
1497a0c41d5SAlan Somers 	if (find_start == string::npos) {
1507a0c41d5SAlan Somers 		find_start = 0;
1517a0c41d5SAlan Somers 	} else {
1527a0c41d5SAlan Somers 		/* Just after the last '/'. */
1537a0c41d5SAlan Somers 		find_start++;
1547a0c41d5SAlan Somers 	}
1557a0c41d5SAlan Somers 
1567a0c41d5SAlan Somers 	for (dName = &diskDevNames[0];
1577a0c41d5SAlan Somers 	     dName <= &diskDevNames[numDrivers - 1]; dName++) {
1587a0c41d5SAlan Somers 
1597a0c41d5SAlan Somers 		size_t loc(devName.find(*dName, find_start));
1607a0c41d5SAlan Somers 		if (loc == find_start) {
1617a0c41d5SAlan Somers 			size_t prefixLen(strlen(*dName));
1627a0c41d5SAlan Somers 
1637a0c41d5SAlan Somers 			if (devName.length() - find_start >= prefixLen
1647a0c41d5SAlan Somers 			 && isdigit(devName[find_start + prefixLen]))
1657a0c41d5SAlan Somers 				return (true);
1667a0c41d5SAlan Somers 		}
1677a0c41d5SAlan Somers 	}
1687a0c41d5SAlan Somers 
1697a0c41d5SAlan Somers 	return (false);
1707a0c41d5SAlan Somers }
1717a0c41d5SAlan Somers 
1727a0c41d5SAlan Somers const char *
1737a0c41d5SAlan Somers Event::TypeToString(Event::Type type)
1747a0c41d5SAlan Somers {
1757a0c41d5SAlan Somers 	EventTypeRecord *rec(s_typeTable);
1767a0c41d5SAlan Somers 	EventTypeRecord *lastRec(s_typeTable + NUM_ELEMENTS(s_typeTable) - 1);
1777a0c41d5SAlan Somers 
1787a0c41d5SAlan Somers 	for (; rec <= lastRec; rec++) {
1797a0c41d5SAlan Somers 		if (rec->m_type == type)
1807a0c41d5SAlan Somers 			return (rec->m_typeName);
1817a0c41d5SAlan Somers 	}
1827a0c41d5SAlan Somers 	return ("Unknown");
1837a0c41d5SAlan Somers }
1847a0c41d5SAlan Somers 
1857a0c41d5SAlan Somers //- Event Public Methods -------------------------------------------------------
1867a0c41d5SAlan Somers const string &
1877a0c41d5SAlan Somers Event::Value(const string &varName) const
1887a0c41d5SAlan Somers {
1897a0c41d5SAlan Somers 	NVPairMap::const_iterator item(m_nvPairs.find(varName));
1907a0c41d5SAlan Somers 	if (item == m_nvPairs.end())
1917a0c41d5SAlan Somers 		return (s_theEmptyString);
1927a0c41d5SAlan Somers 
1937a0c41d5SAlan Somers 	return (item->second);
1947a0c41d5SAlan Somers }
1957a0c41d5SAlan Somers 
1967a0c41d5SAlan Somers bool
1977a0c41d5SAlan Somers Event::Contains(const string &varName) const
1987a0c41d5SAlan Somers {
1997a0c41d5SAlan Somers 	return (m_nvPairs.find(varName) != m_nvPairs.end());
2007a0c41d5SAlan Somers }
2017a0c41d5SAlan Somers 
2027a0c41d5SAlan Somers string
2037a0c41d5SAlan Somers Event::ToString() const
2047a0c41d5SAlan Somers {
2057a0c41d5SAlan Somers 	stringstream result;
2067a0c41d5SAlan Somers 
2077a0c41d5SAlan Somers 	NVPairMap::const_iterator devName(m_nvPairs.find("device-name"));
2087a0c41d5SAlan Somers 	if (devName != m_nvPairs.end())
2097a0c41d5SAlan Somers 		result << devName->second << ": ";
2107a0c41d5SAlan Somers 
2117a0c41d5SAlan Somers 	NVPairMap::const_iterator systemName(m_nvPairs.find("system"));
2127a0c41d5SAlan Somers 	if (systemName != m_nvPairs.end()
2137a0c41d5SAlan Somers 	 && systemName->second != "none")
2147a0c41d5SAlan Somers 		result << systemName->second << ": ";
2157a0c41d5SAlan Somers 
2167a0c41d5SAlan Somers 	result << TypeToString(GetType()) << ' ';
2177a0c41d5SAlan Somers 
2187a0c41d5SAlan Somers 	for (NVPairMap::const_iterator curVar = m_nvPairs.begin();
2197a0c41d5SAlan Somers 	     curVar != m_nvPairs.end(); curVar++) {
2207a0c41d5SAlan Somers 		if (curVar == devName || curVar == systemName)
2217a0c41d5SAlan Somers 			continue;
2227a0c41d5SAlan Somers 
2237a0c41d5SAlan Somers 		result << ' '
2247a0c41d5SAlan Somers 		     << curVar->first << "=" << curVar->second;
2257a0c41d5SAlan Somers 	}
2267a0c41d5SAlan Somers 	result << endl;
2277a0c41d5SAlan Somers 
2287a0c41d5SAlan Somers 	return (result.str());
2297a0c41d5SAlan Somers }
2307a0c41d5SAlan Somers 
2317a0c41d5SAlan Somers void
2327a0c41d5SAlan Somers Event::Print() const
2337a0c41d5SAlan Somers {
2347a0c41d5SAlan Somers 	cout << ToString() << std::flush;
2357a0c41d5SAlan Somers }
2367a0c41d5SAlan Somers 
2377a0c41d5SAlan Somers void
2387a0c41d5SAlan Somers Event::Log(int priority) const
2397a0c41d5SAlan Somers {
2407a0c41d5SAlan Somers 	syslog(priority, "%s", ToString().c_str());
2417a0c41d5SAlan Somers }
2427a0c41d5SAlan Somers 
2437a0c41d5SAlan Somers //- Event Virtual Public Methods -----------------------------------------------
2447a0c41d5SAlan Somers Event::~Event()
2457a0c41d5SAlan Somers {
2467a0c41d5SAlan Somers 	delete &m_nvPairs;
2477a0c41d5SAlan Somers }
2487a0c41d5SAlan Somers 
2497a0c41d5SAlan Somers Event *
2507a0c41d5SAlan Somers Event::DeepCopy() const
2517a0c41d5SAlan Somers {
2527a0c41d5SAlan Somers 	return (new Event(*this));
2537a0c41d5SAlan Somers }
2547a0c41d5SAlan Somers 
2557a0c41d5SAlan Somers bool
2567a0c41d5SAlan Somers Event::Process() const
2577a0c41d5SAlan Somers {
2587a0c41d5SAlan Somers 	return (false);
2597a0c41d5SAlan Somers }
2607a0c41d5SAlan Somers 
2617a0c41d5SAlan Somers timeval
2627a0c41d5SAlan Somers Event::GetTimestamp() const
2637a0c41d5SAlan Somers {
2647a0c41d5SAlan Somers 	timeval tv_timestamp;
2657a0c41d5SAlan Somers 	struct tm tm_timestamp;
2667a0c41d5SAlan Somers 
2677a0c41d5SAlan Somers 	if (!Contains("timestamp")) {
2687a0c41d5SAlan Somers 		throw Exception("Event contains no timestamp: %s",
2697a0c41d5SAlan Somers 				m_eventString.c_str());
2707a0c41d5SAlan Somers 	}
2717a0c41d5SAlan Somers 	strptime(Value(string("timestamp")).c_str(), "%s", &tm_timestamp);
2727a0c41d5SAlan Somers 	tv_timestamp.tv_sec = mktime(&tm_timestamp);
2737a0c41d5SAlan Somers 	tv_timestamp.tv_usec = 0;
2747a0c41d5SAlan Somers 	return (tv_timestamp);
2757a0c41d5SAlan Somers }
2767a0c41d5SAlan Somers 
2777a0c41d5SAlan Somers bool
2787a0c41d5SAlan Somers Event::DevPath(std::string &path) const
2797a0c41d5SAlan Somers {
280*e49d3eb4SAlexander Motin 	char buf[SPECNAMELEN + 1];
2817a0c41d5SAlan Somers 	string devName;
2827a0c41d5SAlan Somers 
2837a0c41d5SAlan Somers 	if (!DevName(devName))
2847a0c41d5SAlan Somers 		return (false);
2857a0c41d5SAlan Somers 
2867a0c41d5SAlan Somers 	string devPath(_PATH_DEV + devName);
2877a0c41d5SAlan Somers 	int devFd(open(devPath.c_str(), O_RDONLY));
2887a0c41d5SAlan Somers 	if (devFd == -1)
2897a0c41d5SAlan Somers 		return (false);
2907a0c41d5SAlan Somers 
2917a0c41d5SAlan Somers 	/* Normalize the device name in case the DEVFS event is for a link. */
292*e49d3eb4SAlexander Motin 	if (fdevname_r(devFd, buf, sizeof(buf)) == NULL) {
293*e49d3eb4SAlexander Motin 		close(devFd);
294*e49d3eb4SAlexander Motin 		return (false);
295*e49d3eb4SAlexander Motin 	}
296*e49d3eb4SAlexander Motin 	devName = buf;
2977a0c41d5SAlan Somers 	path = _PATH_DEV + devName;
2987a0c41d5SAlan Somers 
2997a0c41d5SAlan Somers 	close(devFd);
3007a0c41d5SAlan Somers 
3017a0c41d5SAlan Somers 	return (true);
3027a0c41d5SAlan Somers }
3037a0c41d5SAlan Somers 
3047a0c41d5SAlan Somers bool
3057a0c41d5SAlan Somers Event::PhysicalPath(std::string &path) const
3067a0c41d5SAlan Somers {
3077a0c41d5SAlan Somers 	string devPath;
3087a0c41d5SAlan Somers 
3097a0c41d5SAlan Somers 	if (!DevPath(devPath))
3107a0c41d5SAlan Somers 		return (false);
3117a0c41d5SAlan Somers 
3127a0c41d5SAlan Somers 	int devFd(open(devPath.c_str(), O_RDONLY));
3137a0c41d5SAlan Somers 	if (devFd == -1)
3147a0c41d5SAlan Somers 		return (false);
3157a0c41d5SAlan Somers 
3167a0c41d5SAlan Somers 	char physPath[MAXPATHLEN];
3177a0c41d5SAlan Somers 	physPath[0] = '\0';
3187a0c41d5SAlan Somers 	bool result(ioctl(devFd, DIOCGPHYSPATH, physPath) == 0);
3197a0c41d5SAlan Somers 	close(devFd);
3207a0c41d5SAlan Somers 	if (result)
3217a0c41d5SAlan Somers 		path = physPath;
3227a0c41d5SAlan Somers 	return (result);
3237a0c41d5SAlan Somers }
3247a0c41d5SAlan Somers 
3257a0c41d5SAlan Somers //- Event Protected Methods ----------------------------------------------------
3267a0c41d5SAlan Somers Event::Event(Type type, NVPairMap &map, const string &eventString)
3277a0c41d5SAlan Somers  : m_type(type),
3287a0c41d5SAlan Somers    m_nvPairs(map),
3297a0c41d5SAlan Somers    m_eventString(eventString)
3307a0c41d5SAlan Somers {
3317a0c41d5SAlan Somers }
3327a0c41d5SAlan Somers 
3337a0c41d5SAlan Somers Event::Event(const Event &src)
3347a0c41d5SAlan Somers  : m_type(src.m_type),
3357a0c41d5SAlan Somers    m_nvPairs(*new NVPairMap(src.m_nvPairs)),
3367a0c41d5SAlan Somers    m_eventString(src.m_eventString)
3377a0c41d5SAlan Somers {
3387a0c41d5SAlan Somers }
3397a0c41d5SAlan Somers 
3407a0c41d5SAlan Somers void
3417a0c41d5SAlan Somers Event::ParseEventString(Event::Type type,
3427a0c41d5SAlan Somers 			      const string &eventString,
3437a0c41d5SAlan Somers 			      NVPairMap& nvpairs)
3447a0c41d5SAlan Somers {
3457a0c41d5SAlan Somers 	size_t start;
3467a0c41d5SAlan Somers 	size_t end;
3477a0c41d5SAlan Somers 
3487a0c41d5SAlan Somers 	switch (type) {
3497a0c41d5SAlan Somers 	case ATTACH:
3507a0c41d5SAlan Somers 	case DETACH:
3517a0c41d5SAlan Somers 
3527a0c41d5SAlan Somers 		/*
3537a0c41d5SAlan Somers 		 * <type><device-name><unit> <pnpvars> \
3547a0c41d5SAlan Somers 		 *                        at <location vars> <pnpvars> \
3557a0c41d5SAlan Somers 		 *                        on <parent>
3567a0c41d5SAlan Somers 		 *
3577a0c41d5SAlan Somers 		 * Handle all data that doesn't conform to the
3587a0c41d5SAlan Somers 		 * "name=value" format, and let the generic parser
3597a0c41d5SAlan Somers 		 * below handle the rest.
3607a0c41d5SAlan Somers 		 *
3617a0c41d5SAlan Somers 		 * Type is a single char.  Skip it.
3627a0c41d5SAlan Somers 		 */
3637a0c41d5SAlan Somers 		start = 1;
3647a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
3657a0c41d5SAlan Somers 		if (end == string::npos)
3667a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
3677a0c41d5SAlan Somers 					     eventString, start);
3687a0c41d5SAlan Somers 
3697a0c41d5SAlan Somers 		nvpairs["device-name"] = eventString.substr(start, end - start);
3707a0c41d5SAlan Somers 
3717a0c41d5SAlan Somers 		start = eventString.find(" on ", end);
3727a0c41d5SAlan Somers 		if (end == string::npos)
3737a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
3747a0c41d5SAlan Somers 					     eventString, start);
3757a0c41d5SAlan Somers 		start += 4;
3767a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
3777a0c41d5SAlan Somers 		nvpairs["parent"] = eventString.substr(start, end);
3787a0c41d5SAlan Somers 		break;
3797a0c41d5SAlan Somers 	case NOTIFY:
3807a0c41d5SAlan Somers 		break;
3817a0c41d5SAlan Somers 	case NOMATCH:
3827a0c41d5SAlan Somers 		throw ParseException(ParseException::DISCARDED_EVENT_TYPE,
3837a0c41d5SAlan Somers 				     eventString);
3847a0c41d5SAlan Somers 	default:
3857a0c41d5SAlan Somers 		throw ParseException(ParseException::UNKNOWN_EVENT_TYPE,
3867a0c41d5SAlan Somers 				     eventString);
3877a0c41d5SAlan Somers 	}
3887a0c41d5SAlan Somers 
3897a0c41d5SAlan Somers 	/* Process common "key=value" format. */
3907a0c41d5SAlan Somers 	for (start = 1; start < eventString.length(); start = end + 1) {
3917a0c41d5SAlan Somers 
3927a0c41d5SAlan Somers 		/* Find the '=' in the middle of the key/value pair. */
3937a0c41d5SAlan Somers 		end = eventString.find('=', start);
3947a0c41d5SAlan Somers 		if (end == string::npos)
3957a0c41d5SAlan Somers 			break;
3967a0c41d5SAlan Somers 
3977a0c41d5SAlan Somers 		/*
3987a0c41d5SAlan Somers 		 * Find the start of the key by backing up until
3997a0c41d5SAlan Somers 		 * we hit whitespace or '!' (event type "notice").
4007a0c41d5SAlan Somers 		 * Due to the devdctl format, all key/value pair must
4017a0c41d5SAlan Somers 		 * start with one of these two characters.
4027a0c41d5SAlan Somers 		 */
4037a0c41d5SAlan Somers 		start = eventString.find_last_of("! \t\n", end);
4047a0c41d5SAlan Somers 		if (start == string::npos)
4057a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
4067a0c41d5SAlan Somers 					     eventString, end);
4077a0c41d5SAlan Somers 		start++;
4087a0c41d5SAlan Somers 		string key(eventString.substr(start, end - start));
4097a0c41d5SAlan Somers 
4107a0c41d5SAlan Somers 		/*
4117a0c41d5SAlan Somers 		 * Walk forward from the '=' until either we exhaust
4127a0c41d5SAlan Somers 		 * the buffer or we hit whitespace.
4137a0c41d5SAlan Somers 		 */
4147a0c41d5SAlan Somers 		start = end + 1;
4157a0c41d5SAlan Somers 		if (start >= eventString.length())
4167a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
4177a0c41d5SAlan Somers 					     eventString, end);
4187a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
4197a0c41d5SAlan Somers 		if (end == string::npos)
4207a0c41d5SAlan Somers 			end = eventString.length() - 1;
4217a0c41d5SAlan Somers 		string value(eventString.substr(start, end - start));
4227a0c41d5SAlan Somers 
4237a0c41d5SAlan Somers 		nvpairs[key] = value;
4247a0c41d5SAlan Somers 	}
4257a0c41d5SAlan Somers }
4267a0c41d5SAlan Somers 
4277a0c41d5SAlan Somers void
4287a0c41d5SAlan Somers Event::TimestampEventString(std::string &eventString)
4297a0c41d5SAlan Somers {
4307a0c41d5SAlan Somers 	if (eventString.size() > 0) {
4317a0c41d5SAlan Somers 		/*
4327a0c41d5SAlan Somers 		 * Add a timestamp as the final field of the event if it is
4337a0c41d5SAlan Somers 		 * not already present.
4347a0c41d5SAlan Somers 		 */
4357a0c41d5SAlan Somers 		if (eventString.find(" timestamp=") == string::npos) {
4367a0c41d5SAlan Somers 			const size_t bufsize = 32;	// Long enough for a 64-bit int
4377a0c41d5SAlan Somers 			timeval now;
4387a0c41d5SAlan Somers 			char timebuf[bufsize];
4397a0c41d5SAlan Somers 
4407a0c41d5SAlan Somers 			size_t eventEnd(eventString.find_last_not_of('\n') + 1);
4417a0c41d5SAlan Somers 			if (gettimeofday(&now, NULL) != 0)
4427a0c41d5SAlan Somers 				err(1, "gettimeofday");
4437a0c41d5SAlan Somers 			snprintf(timebuf, bufsize, " timestamp=%" PRId64,
4447a0c41d5SAlan Somers 				(int64_t) now.tv_sec);
4457a0c41d5SAlan Somers 			eventString.insert(eventEnd, timebuf);
4467a0c41d5SAlan Somers 		}
4477a0c41d5SAlan Somers 	}
4487a0c41d5SAlan Somers }
4497a0c41d5SAlan Somers 
4507a0c41d5SAlan Somers /*-------------------------------- DevfsEvent --------------------------------*/
4517a0c41d5SAlan Somers //- DevfsEvent Static Public Methods -------------------------------------------
4527a0c41d5SAlan Somers Event *
4537a0c41d5SAlan Somers DevfsEvent::Builder(Event::Type type, NVPairMap &nvPairs,
4547a0c41d5SAlan Somers 		    const string &eventString)
4557a0c41d5SAlan Somers {
4567a0c41d5SAlan Somers 	return (new DevfsEvent(type, nvPairs, eventString));
4577a0c41d5SAlan Somers }
4587a0c41d5SAlan Somers 
4597a0c41d5SAlan Somers //- DevfsEvent Static Protected Methods ----------------------------------------
4607a0c41d5SAlan Somers bool
4617a0c41d5SAlan Somers DevfsEvent::IsWholeDev(const string &devName)
4627a0c41d5SAlan Somers {
4637a0c41d5SAlan Somers 	string::const_iterator i(devName.begin());
4647a0c41d5SAlan Somers 
4657a0c41d5SAlan Somers 	size_t start = devName.rfind('/');
4667a0c41d5SAlan Somers 	if (start == string::npos) {
4677a0c41d5SAlan Somers 		start = 0;
4687a0c41d5SAlan Somers 	} else {
4697a0c41d5SAlan Somers 		/* Just after the last '/'. */
4707a0c41d5SAlan Somers 		start++;
4717a0c41d5SAlan Somers 	}
4727a0c41d5SAlan Somers 	i += start;
4737a0c41d5SAlan Somers 
4747a0c41d5SAlan Somers 	/* alpha prefix followed only by digits. */
4757a0c41d5SAlan Somers 	for (; i < devName.end() && !isdigit(*i); i++)
4767a0c41d5SAlan Somers 		;
4777a0c41d5SAlan Somers 
4787a0c41d5SAlan Somers 	if (i == devName.end())
4797a0c41d5SAlan Somers 		return (false);
4807a0c41d5SAlan Somers 
4817a0c41d5SAlan Somers 	for (; i < devName.end() && isdigit(*i); i++)
4827a0c41d5SAlan Somers 		;
4837a0c41d5SAlan Somers 
4847a0c41d5SAlan Somers 	return (i == devName.end());
4857a0c41d5SAlan Somers }
4867a0c41d5SAlan Somers 
4877a0c41d5SAlan Somers //- DevfsEvent Virtual Public Methods ------------------------------------------
4887a0c41d5SAlan Somers Event *
4897a0c41d5SAlan Somers DevfsEvent::DeepCopy() const
4907a0c41d5SAlan Somers {
4917a0c41d5SAlan Somers 	return (new DevfsEvent(*this));
4927a0c41d5SAlan Somers }
4937a0c41d5SAlan Somers 
4947a0c41d5SAlan Somers bool
4957a0c41d5SAlan Somers DevfsEvent::Process() const
4967a0c41d5SAlan Somers {
4977a0c41d5SAlan Somers 	return (true);
4987a0c41d5SAlan Somers }
4997a0c41d5SAlan Somers 
5007a0c41d5SAlan Somers //- DevfsEvent Public Methods --------------------------------------------------
5017a0c41d5SAlan Somers bool
5027a0c41d5SAlan Somers DevfsEvent::IsWholeDev() const
5037a0c41d5SAlan Somers {
5047a0c41d5SAlan Somers 	string devName;
5057a0c41d5SAlan Somers 
5067a0c41d5SAlan Somers 	return (DevName(devName) && IsDiskDev() && IsWholeDev(devName));
5077a0c41d5SAlan Somers }
5087a0c41d5SAlan Somers 
5097a0c41d5SAlan Somers bool
5107a0c41d5SAlan Somers DevfsEvent::DevName(std::string &name) const
5117a0c41d5SAlan Somers {
5127a0c41d5SAlan Somers 	if (Value("subsystem") != "CDEV")
5137a0c41d5SAlan Somers 		return (false);
5147a0c41d5SAlan Somers 
5157a0c41d5SAlan Somers 	name = Value("cdev");
5167a0c41d5SAlan Somers 	return (!name.empty());
5177a0c41d5SAlan Somers }
5187a0c41d5SAlan Somers 
5197a0c41d5SAlan Somers //- DevfsEvent Protected Methods -----------------------------------------------
5207a0c41d5SAlan Somers DevfsEvent::DevfsEvent(Event::Type type, NVPairMap &nvpairs,
5217a0c41d5SAlan Somers 		       const string &eventString)
5227a0c41d5SAlan Somers  : Event(type, nvpairs, eventString)
5237a0c41d5SAlan Somers {
5247a0c41d5SAlan Somers }
5257a0c41d5SAlan Somers 
5267a0c41d5SAlan Somers DevfsEvent::DevfsEvent(const DevfsEvent &src)
5277a0c41d5SAlan Somers  : Event(src)
5287a0c41d5SAlan Somers {
5297a0c41d5SAlan Somers }
5307a0c41d5SAlan Somers 
5317a0c41d5SAlan Somers /*--------------------------------- GeomEvent --------------------------------*/
5327a0c41d5SAlan Somers //- GeomEvent Static Public Methods --------------------------------------------
5337a0c41d5SAlan Somers Event *
5347a0c41d5SAlan Somers GeomEvent::Builder(Event::Type type, NVPairMap &nvpairs,
5357a0c41d5SAlan Somers 		   const string &eventString)
5367a0c41d5SAlan Somers {
5377a0c41d5SAlan Somers 	return (new GeomEvent(type, nvpairs, eventString));
5387a0c41d5SAlan Somers }
5397a0c41d5SAlan Somers 
5407a0c41d5SAlan Somers //- GeomEvent Virtual Public Methods -------------------------------------------
5417a0c41d5SAlan Somers Event *
5427a0c41d5SAlan Somers GeomEvent::DeepCopy() const
5437a0c41d5SAlan Somers {
5447a0c41d5SAlan Somers 	return (new GeomEvent(*this));
5457a0c41d5SAlan Somers }
5467a0c41d5SAlan Somers 
5477a0c41d5SAlan Somers bool
5487a0c41d5SAlan Somers GeomEvent::DevName(std::string &name) const
5497a0c41d5SAlan Somers {
550a07d59d1SAlan Somers 	if (Value("subsystem") == "disk")
5517a0c41d5SAlan Somers 		name = Value("devname");
552a07d59d1SAlan Somers 	else
553a07d59d1SAlan Somers 		name = Value("cdev");
5547a0c41d5SAlan Somers 	return (!name.empty());
5557a0c41d5SAlan Somers }
5567a0c41d5SAlan Somers 
5577a0c41d5SAlan Somers 
5587a0c41d5SAlan Somers //- GeomEvent Protected Methods ------------------------------------------------
5597a0c41d5SAlan Somers GeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs,
5607a0c41d5SAlan Somers 		     const string &eventString)
5617a0c41d5SAlan Somers  : Event(type, nvpairs, eventString),
5627a0c41d5SAlan Somers    m_devname(Value("devname"))
5637a0c41d5SAlan Somers {
5647a0c41d5SAlan Somers }
5657a0c41d5SAlan Somers 
5667a0c41d5SAlan Somers GeomEvent::GeomEvent(const GeomEvent &src)
5677a0c41d5SAlan Somers  : Event(src),
5687a0c41d5SAlan Somers    m_devname(src.m_devname)
5697a0c41d5SAlan Somers {
5707a0c41d5SAlan Somers }
5717a0c41d5SAlan Somers 
5727a0c41d5SAlan Somers /*--------------------------------- ZfsEvent ---------------------------------*/
5737a0c41d5SAlan Somers //- ZfsEvent Static Public Methods ---------------------------------------------
5747a0c41d5SAlan Somers Event *
5757a0c41d5SAlan Somers ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs,
5767a0c41d5SAlan Somers 		  const string &eventString)
5777a0c41d5SAlan Somers {
5787a0c41d5SAlan Somers 	return (new ZfsEvent(type, nvpairs, eventString));
5797a0c41d5SAlan Somers }
5807a0c41d5SAlan Somers 
5817a0c41d5SAlan Somers //- ZfsEvent Virtual Public Methods --------------------------------------------
5827a0c41d5SAlan Somers Event *
5837a0c41d5SAlan Somers ZfsEvent::DeepCopy() const
5847a0c41d5SAlan Somers {
5857a0c41d5SAlan Somers 	return (new ZfsEvent(*this));
5867a0c41d5SAlan Somers }
5877a0c41d5SAlan Somers 
5887a0c41d5SAlan Somers bool
5897a0c41d5SAlan Somers ZfsEvent::DevName(std::string &name) const
5907a0c41d5SAlan Somers {
5917a0c41d5SAlan Somers 	return (false);
5927a0c41d5SAlan Somers }
5937a0c41d5SAlan Somers 
5947a0c41d5SAlan Somers //- ZfsEvent Protected Methods -------------------------------------------------
5957a0c41d5SAlan Somers ZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs,
5967a0c41d5SAlan Somers 		   const string &eventString)
5977a0c41d5SAlan Somers  : Event(type, nvpairs, eventString),
5987a0c41d5SAlan Somers    m_poolGUID(Guid(Value("pool_guid"))),
5997a0c41d5SAlan Somers    m_vdevGUID(Guid(Value("vdev_guid")))
6007a0c41d5SAlan Somers {
6017a0c41d5SAlan Somers }
6027a0c41d5SAlan Somers 
6037a0c41d5SAlan Somers ZfsEvent::ZfsEvent(const ZfsEvent &src)
6047a0c41d5SAlan Somers  : Event(src),
6057a0c41d5SAlan Somers    m_poolGUID(src.m_poolGUID),
6067a0c41d5SAlan Somers    m_vdevGUID(src.m_vdevGUID)
6077a0c41d5SAlan Somers {
6087a0c41d5SAlan Somers }
6097a0c41d5SAlan Somers 
6107a0c41d5SAlan Somers } // namespace DevdCtl
611