xref: /freebsd-14.2/lib/libdevdctl/event.cc (revision 7a0c41d5)
1*7a0c41d5SAlan Somers /*-
2*7a0c41d5SAlan Somers  * Copyright (c) 2011, 2012, 2013, 2016 Spectra Logic Corporation
3*7a0c41d5SAlan Somers  * All rights reserved.
4*7a0c41d5SAlan Somers  *
5*7a0c41d5SAlan Somers  * Redistribution and use in source and binary forms, with or without
6*7a0c41d5SAlan Somers  * modification, are permitted provided that the following conditions
7*7a0c41d5SAlan Somers  * are met:
8*7a0c41d5SAlan Somers  * 1. Redistributions of source code must retain the above copyright
9*7a0c41d5SAlan Somers  *    notice, this list of conditions, and the following disclaimer,
10*7a0c41d5SAlan Somers  *    without modification.
11*7a0c41d5SAlan Somers  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12*7a0c41d5SAlan Somers  *    substantially similar to the "NO WARRANTY" disclaimer below
13*7a0c41d5SAlan Somers  *    ("Disclaimer") and any redistribution must be conditioned upon
14*7a0c41d5SAlan Somers  *    including a substantially similar Disclaimer requirement for further
15*7a0c41d5SAlan Somers  *    binary redistribution.
16*7a0c41d5SAlan Somers  *
17*7a0c41d5SAlan Somers  * NO WARRANTY
18*7a0c41d5SAlan Somers  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19*7a0c41d5SAlan Somers  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20*7a0c41d5SAlan Somers  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21*7a0c41d5SAlan Somers  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22*7a0c41d5SAlan Somers  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*7a0c41d5SAlan Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*7a0c41d5SAlan Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*7a0c41d5SAlan Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26*7a0c41d5SAlan Somers  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27*7a0c41d5SAlan Somers  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*7a0c41d5SAlan Somers  * POSSIBILITY OF SUCH DAMAGES.
29*7a0c41d5SAlan Somers  *
30*7a0c41d5SAlan Somers  * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
31*7a0c41d5SAlan Somers  */
32*7a0c41d5SAlan Somers 
33*7a0c41d5SAlan Somers /**
34*7a0c41d5SAlan Somers  * \file event.cc
35*7a0c41d5SAlan Somers  *
36*7a0c41d5SAlan Somers  * Implementation of the class hierarchy used to express events
37*7a0c41d5SAlan Somers  * received via the devdctl API.
38*7a0c41d5SAlan Somers  */
39*7a0c41d5SAlan Somers #include <sys/cdefs.h>
40*7a0c41d5SAlan Somers #include <sys/disk.h>
41*7a0c41d5SAlan Somers #include <sys/filio.h>
42*7a0c41d5SAlan Somers #include <sys/param.h>
43*7a0c41d5SAlan Somers #include <sys/stat.h>
44*7a0c41d5SAlan Somers 
45*7a0c41d5SAlan Somers #include <err.h>
46*7a0c41d5SAlan Somers #include <fcntl.h>
47*7a0c41d5SAlan Somers #include <inttypes.h>
48*7a0c41d5SAlan Somers #include <paths.h>
49*7a0c41d5SAlan Somers #include <stdlib.h>
50*7a0c41d5SAlan Somers #include <syslog.h>
51*7a0c41d5SAlan Somers #include <unistd.h>
52*7a0c41d5SAlan Somers 
53*7a0c41d5SAlan Somers #include <cstdarg>
54*7a0c41d5SAlan Somers #include <cstring>
55*7a0c41d5SAlan Somers #include <iostream>
56*7a0c41d5SAlan Somers #include <list>
57*7a0c41d5SAlan Somers #include <map>
58*7a0c41d5SAlan Somers #include <sstream>
59*7a0c41d5SAlan Somers #include <string>
60*7a0c41d5SAlan Somers 
61*7a0c41d5SAlan Somers #include "guid.h"
62*7a0c41d5SAlan Somers #include "event.h"
63*7a0c41d5SAlan Somers #include "event_factory.h"
64*7a0c41d5SAlan Somers #include "exception.h"
65*7a0c41d5SAlan Somers 
66*7a0c41d5SAlan Somers __FBSDID("$FreeBSD$");
67*7a0c41d5SAlan Somers 
68*7a0c41d5SAlan Somers /*================================== Macros ==================================*/
69*7a0c41d5SAlan Somers #define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))
70*7a0c41d5SAlan Somers 
71*7a0c41d5SAlan Somers /*============================ Namespace Control =============================*/
72*7a0c41d5SAlan Somers using std::cout;
73*7a0c41d5SAlan Somers using std::endl;
74*7a0c41d5SAlan Somers using std::string;
75*7a0c41d5SAlan Somers using std::stringstream;
76*7a0c41d5SAlan Somers 
77*7a0c41d5SAlan Somers namespace DevdCtl
78*7a0c41d5SAlan Somers {
79*7a0c41d5SAlan Somers 
80*7a0c41d5SAlan Somers /*=========================== Class Implementations ==========================*/
81*7a0c41d5SAlan Somers /*----------------------------------- Event ----------------------------------*/
82*7a0c41d5SAlan Somers //- Event Static Protected Data ------------------------------------------------
83*7a0c41d5SAlan Somers const string Event::s_theEmptyString;
84*7a0c41d5SAlan Somers 
85*7a0c41d5SAlan Somers Event::EventTypeRecord Event::s_typeTable[] =
86*7a0c41d5SAlan Somers {
87*7a0c41d5SAlan Somers 	{ Event::NOTIFY,  "Notify" },
88*7a0c41d5SAlan Somers 	{ Event::NOMATCH, "No Driver Match" },
89*7a0c41d5SAlan Somers 	{ Event::ATTACH,  "Attach" },
90*7a0c41d5SAlan Somers 	{ Event::DETACH,  "Detach" }
91*7a0c41d5SAlan Somers };
92*7a0c41d5SAlan Somers 
93*7a0c41d5SAlan Somers //- Event Static Public Methods ------------------------------------------------
94*7a0c41d5SAlan Somers Event *
95*7a0c41d5SAlan Somers Event::Builder(Event::Type type, NVPairMap &nvPairs,
96*7a0c41d5SAlan Somers 	       const string &eventString)
97*7a0c41d5SAlan Somers {
98*7a0c41d5SAlan Somers 	return (new Event(type, nvPairs, eventString));
99*7a0c41d5SAlan Somers }
100*7a0c41d5SAlan Somers 
101*7a0c41d5SAlan Somers Event *
102*7a0c41d5SAlan Somers Event::CreateEvent(const EventFactory &factory, const string &eventString)
103*7a0c41d5SAlan Somers {
104*7a0c41d5SAlan Somers 	NVPairMap &nvpairs(*new NVPairMap);
105*7a0c41d5SAlan Somers 	Type       type(static_cast<Event::Type>(eventString[0]));
106*7a0c41d5SAlan Somers 
107*7a0c41d5SAlan Somers 	try {
108*7a0c41d5SAlan Somers 		ParseEventString(type, eventString, nvpairs);
109*7a0c41d5SAlan Somers 	} catch (const ParseException &exp) {
110*7a0c41d5SAlan Somers 		if (exp.GetType() == ParseException::INVALID_FORMAT)
111*7a0c41d5SAlan Somers 			exp.Log();
112*7a0c41d5SAlan Somers 		return (NULL);
113*7a0c41d5SAlan Somers 	}
114*7a0c41d5SAlan Somers 
115*7a0c41d5SAlan Somers 	/*
116*7a0c41d5SAlan Somers 	 * Allow entries in our table for events with no system specified.
117*7a0c41d5SAlan Somers 	 * These entries should specify the string "none".
118*7a0c41d5SAlan Somers 	 */
119*7a0c41d5SAlan Somers 	NVPairMap::iterator system_item(nvpairs.find("system"));
120*7a0c41d5SAlan Somers 	if (system_item == nvpairs.end())
121*7a0c41d5SAlan Somers 		nvpairs["system"] = "none";
122*7a0c41d5SAlan Somers 
123*7a0c41d5SAlan Somers 	return (factory.Build(type, nvpairs, eventString));
124*7a0c41d5SAlan Somers }
125*7a0c41d5SAlan Somers 
126*7a0c41d5SAlan Somers bool
127*7a0c41d5SAlan Somers Event::DevName(std::string &name) const
128*7a0c41d5SAlan Somers {
129*7a0c41d5SAlan Somers 	return (false);
130*7a0c41d5SAlan Somers }
131*7a0c41d5SAlan Somers 
132*7a0c41d5SAlan Somers /* TODO: simplify this function with C++-11 <regex> methods */
133*7a0c41d5SAlan Somers bool
134*7a0c41d5SAlan Somers Event::IsDiskDev() const
135*7a0c41d5SAlan Somers {
136*7a0c41d5SAlan Somers 	const int numDrivers = 2;
137*7a0c41d5SAlan Somers 	static const char *diskDevNames[numDrivers] =
138*7a0c41d5SAlan Somers 	{
139*7a0c41d5SAlan Somers 		"da",
140*7a0c41d5SAlan Somers 		"ada"
141*7a0c41d5SAlan Somers 	};
142*7a0c41d5SAlan Somers 	const char **dName;
143*7a0c41d5SAlan Somers 	string devName;
144*7a0c41d5SAlan Somers 
145*7a0c41d5SAlan Somers 	if (! DevName(devName))
146*7a0c41d5SAlan Somers 		return false;
147*7a0c41d5SAlan Somers 
148*7a0c41d5SAlan Somers 	size_t find_start = devName.rfind('/');
149*7a0c41d5SAlan Somers 	if (find_start == string::npos) {
150*7a0c41d5SAlan Somers 		find_start = 0;
151*7a0c41d5SAlan Somers 	} else {
152*7a0c41d5SAlan Somers 		/* Just after the last '/'. */
153*7a0c41d5SAlan Somers 		find_start++;
154*7a0c41d5SAlan Somers 	}
155*7a0c41d5SAlan Somers 
156*7a0c41d5SAlan Somers 	for (dName = &diskDevNames[0];
157*7a0c41d5SAlan Somers 	     dName <= &diskDevNames[numDrivers - 1]; dName++) {
158*7a0c41d5SAlan Somers 
159*7a0c41d5SAlan Somers 		size_t loc(devName.find(*dName, find_start));
160*7a0c41d5SAlan Somers 		if (loc == find_start) {
161*7a0c41d5SAlan Somers 			size_t prefixLen(strlen(*dName));
162*7a0c41d5SAlan Somers 
163*7a0c41d5SAlan Somers 			if (devName.length() - find_start >= prefixLen
164*7a0c41d5SAlan Somers 			 && isdigit(devName[find_start + prefixLen]))
165*7a0c41d5SAlan Somers 				return (true);
166*7a0c41d5SAlan Somers 		}
167*7a0c41d5SAlan Somers 	}
168*7a0c41d5SAlan Somers 
169*7a0c41d5SAlan Somers 	return (false);
170*7a0c41d5SAlan Somers }
171*7a0c41d5SAlan Somers 
172*7a0c41d5SAlan Somers const char *
173*7a0c41d5SAlan Somers Event::TypeToString(Event::Type type)
174*7a0c41d5SAlan Somers {
175*7a0c41d5SAlan Somers 	EventTypeRecord *rec(s_typeTable);
176*7a0c41d5SAlan Somers 	EventTypeRecord *lastRec(s_typeTable + NUM_ELEMENTS(s_typeTable) - 1);
177*7a0c41d5SAlan Somers 
178*7a0c41d5SAlan Somers 	for (; rec <= lastRec; rec++) {
179*7a0c41d5SAlan Somers 		if (rec->m_type == type)
180*7a0c41d5SAlan Somers 			return (rec->m_typeName);
181*7a0c41d5SAlan Somers 	}
182*7a0c41d5SAlan Somers 	return ("Unknown");
183*7a0c41d5SAlan Somers }
184*7a0c41d5SAlan Somers 
185*7a0c41d5SAlan Somers //- Event Public Methods -------------------------------------------------------
186*7a0c41d5SAlan Somers const string &
187*7a0c41d5SAlan Somers Event::Value(const string &varName) const
188*7a0c41d5SAlan Somers {
189*7a0c41d5SAlan Somers 	NVPairMap::const_iterator item(m_nvPairs.find(varName));
190*7a0c41d5SAlan Somers 	if (item == m_nvPairs.end())
191*7a0c41d5SAlan Somers 		return (s_theEmptyString);
192*7a0c41d5SAlan Somers 
193*7a0c41d5SAlan Somers 	return (item->second);
194*7a0c41d5SAlan Somers }
195*7a0c41d5SAlan Somers 
196*7a0c41d5SAlan Somers bool
197*7a0c41d5SAlan Somers Event::Contains(const string &varName) const
198*7a0c41d5SAlan Somers {
199*7a0c41d5SAlan Somers 	return (m_nvPairs.find(varName) != m_nvPairs.end());
200*7a0c41d5SAlan Somers }
201*7a0c41d5SAlan Somers 
202*7a0c41d5SAlan Somers string
203*7a0c41d5SAlan Somers Event::ToString() const
204*7a0c41d5SAlan Somers {
205*7a0c41d5SAlan Somers 	stringstream result;
206*7a0c41d5SAlan Somers 
207*7a0c41d5SAlan Somers 	NVPairMap::const_iterator devName(m_nvPairs.find("device-name"));
208*7a0c41d5SAlan Somers 	if (devName != m_nvPairs.end())
209*7a0c41d5SAlan Somers 		result << devName->second << ": ";
210*7a0c41d5SAlan Somers 
211*7a0c41d5SAlan Somers 	NVPairMap::const_iterator systemName(m_nvPairs.find("system"));
212*7a0c41d5SAlan Somers 	if (systemName != m_nvPairs.end()
213*7a0c41d5SAlan Somers 	 && systemName->second != "none")
214*7a0c41d5SAlan Somers 		result << systemName->second << ": ";
215*7a0c41d5SAlan Somers 
216*7a0c41d5SAlan Somers 	result << TypeToString(GetType()) << ' ';
217*7a0c41d5SAlan Somers 
218*7a0c41d5SAlan Somers 	for (NVPairMap::const_iterator curVar = m_nvPairs.begin();
219*7a0c41d5SAlan Somers 	     curVar != m_nvPairs.end(); curVar++) {
220*7a0c41d5SAlan Somers 		if (curVar == devName || curVar == systemName)
221*7a0c41d5SAlan Somers 			continue;
222*7a0c41d5SAlan Somers 
223*7a0c41d5SAlan Somers 		result << ' '
224*7a0c41d5SAlan Somers 		     << curVar->first << "=" << curVar->second;
225*7a0c41d5SAlan Somers 	}
226*7a0c41d5SAlan Somers 	result << endl;
227*7a0c41d5SAlan Somers 
228*7a0c41d5SAlan Somers 	return (result.str());
229*7a0c41d5SAlan Somers }
230*7a0c41d5SAlan Somers 
231*7a0c41d5SAlan Somers void
232*7a0c41d5SAlan Somers Event::Print() const
233*7a0c41d5SAlan Somers {
234*7a0c41d5SAlan Somers 	cout << ToString() << std::flush;
235*7a0c41d5SAlan Somers }
236*7a0c41d5SAlan Somers 
237*7a0c41d5SAlan Somers void
238*7a0c41d5SAlan Somers Event::Log(int priority) const
239*7a0c41d5SAlan Somers {
240*7a0c41d5SAlan Somers 	syslog(priority, "%s", ToString().c_str());
241*7a0c41d5SAlan Somers }
242*7a0c41d5SAlan Somers 
243*7a0c41d5SAlan Somers //- Event Virtual Public Methods -----------------------------------------------
244*7a0c41d5SAlan Somers Event::~Event()
245*7a0c41d5SAlan Somers {
246*7a0c41d5SAlan Somers 	delete &m_nvPairs;
247*7a0c41d5SAlan Somers }
248*7a0c41d5SAlan Somers 
249*7a0c41d5SAlan Somers Event *
250*7a0c41d5SAlan Somers Event::DeepCopy() const
251*7a0c41d5SAlan Somers {
252*7a0c41d5SAlan Somers 	return (new Event(*this));
253*7a0c41d5SAlan Somers }
254*7a0c41d5SAlan Somers 
255*7a0c41d5SAlan Somers bool
256*7a0c41d5SAlan Somers Event::Process() const
257*7a0c41d5SAlan Somers {
258*7a0c41d5SAlan Somers 	return (false);
259*7a0c41d5SAlan Somers }
260*7a0c41d5SAlan Somers 
261*7a0c41d5SAlan Somers timeval
262*7a0c41d5SAlan Somers Event::GetTimestamp() const
263*7a0c41d5SAlan Somers {
264*7a0c41d5SAlan Somers 	timeval tv_timestamp;
265*7a0c41d5SAlan Somers 	struct tm tm_timestamp;
266*7a0c41d5SAlan Somers 
267*7a0c41d5SAlan Somers 	if (!Contains("timestamp")) {
268*7a0c41d5SAlan Somers 		throw Exception("Event contains no timestamp: %s",
269*7a0c41d5SAlan Somers 				m_eventString.c_str());
270*7a0c41d5SAlan Somers 	}
271*7a0c41d5SAlan Somers 	strptime(Value(string("timestamp")).c_str(), "%s", &tm_timestamp);
272*7a0c41d5SAlan Somers 	tv_timestamp.tv_sec = mktime(&tm_timestamp);
273*7a0c41d5SAlan Somers 	tv_timestamp.tv_usec = 0;
274*7a0c41d5SAlan Somers 	return (tv_timestamp);
275*7a0c41d5SAlan Somers }
276*7a0c41d5SAlan Somers 
277*7a0c41d5SAlan Somers bool
278*7a0c41d5SAlan Somers Event::DevPath(std::string &path) const
279*7a0c41d5SAlan Somers {
280*7a0c41d5SAlan Somers 	string devName;
281*7a0c41d5SAlan Somers 
282*7a0c41d5SAlan Somers 	if (!DevName(devName))
283*7a0c41d5SAlan Somers 		return (false);
284*7a0c41d5SAlan Somers 
285*7a0c41d5SAlan Somers 	string devPath(_PATH_DEV + devName);
286*7a0c41d5SAlan Somers 	int devFd(open(devPath.c_str(), O_RDONLY));
287*7a0c41d5SAlan Somers 	if (devFd == -1)
288*7a0c41d5SAlan Somers 		return (false);
289*7a0c41d5SAlan Somers 
290*7a0c41d5SAlan Somers 	/* Normalize the device name in case the DEVFS event is for a link. */
291*7a0c41d5SAlan Somers 	devName = fdevname(devFd);
292*7a0c41d5SAlan Somers 	path = _PATH_DEV + devName;
293*7a0c41d5SAlan Somers 
294*7a0c41d5SAlan Somers 	close(devFd);
295*7a0c41d5SAlan Somers 
296*7a0c41d5SAlan Somers 	return (true);
297*7a0c41d5SAlan Somers }
298*7a0c41d5SAlan Somers 
299*7a0c41d5SAlan Somers bool
300*7a0c41d5SAlan Somers Event::PhysicalPath(std::string &path) const
301*7a0c41d5SAlan Somers {
302*7a0c41d5SAlan Somers 	string devPath;
303*7a0c41d5SAlan Somers 
304*7a0c41d5SAlan Somers 	if (!DevPath(devPath))
305*7a0c41d5SAlan Somers 		return (false);
306*7a0c41d5SAlan Somers 
307*7a0c41d5SAlan Somers 	int devFd(open(devPath.c_str(), O_RDONLY));
308*7a0c41d5SAlan Somers 	if (devFd == -1)
309*7a0c41d5SAlan Somers 		return (false);
310*7a0c41d5SAlan Somers 
311*7a0c41d5SAlan Somers 	char physPath[MAXPATHLEN];
312*7a0c41d5SAlan Somers 	physPath[0] = '\0';
313*7a0c41d5SAlan Somers 	bool result(ioctl(devFd, DIOCGPHYSPATH, physPath) == 0);
314*7a0c41d5SAlan Somers 	close(devFd);
315*7a0c41d5SAlan Somers 	if (result)
316*7a0c41d5SAlan Somers 		path = physPath;
317*7a0c41d5SAlan Somers 	return (result);
318*7a0c41d5SAlan Somers }
319*7a0c41d5SAlan Somers 
320*7a0c41d5SAlan Somers //- Event Protected Methods ----------------------------------------------------
321*7a0c41d5SAlan Somers Event::Event(Type type, NVPairMap &map, const string &eventString)
322*7a0c41d5SAlan Somers  : m_type(type),
323*7a0c41d5SAlan Somers    m_nvPairs(map),
324*7a0c41d5SAlan Somers    m_eventString(eventString)
325*7a0c41d5SAlan Somers {
326*7a0c41d5SAlan Somers }
327*7a0c41d5SAlan Somers 
328*7a0c41d5SAlan Somers Event::Event(const Event &src)
329*7a0c41d5SAlan Somers  : m_type(src.m_type),
330*7a0c41d5SAlan Somers    m_nvPairs(*new NVPairMap(src.m_nvPairs)),
331*7a0c41d5SAlan Somers    m_eventString(src.m_eventString)
332*7a0c41d5SAlan Somers {
333*7a0c41d5SAlan Somers }
334*7a0c41d5SAlan Somers 
335*7a0c41d5SAlan Somers void
336*7a0c41d5SAlan Somers Event::ParseEventString(Event::Type type,
337*7a0c41d5SAlan Somers 			      const string &eventString,
338*7a0c41d5SAlan Somers 			      NVPairMap& nvpairs)
339*7a0c41d5SAlan Somers {
340*7a0c41d5SAlan Somers 	size_t start;
341*7a0c41d5SAlan Somers 	size_t end;
342*7a0c41d5SAlan Somers 
343*7a0c41d5SAlan Somers 	switch (type) {
344*7a0c41d5SAlan Somers 	case ATTACH:
345*7a0c41d5SAlan Somers 	case DETACH:
346*7a0c41d5SAlan Somers 
347*7a0c41d5SAlan Somers 		/*
348*7a0c41d5SAlan Somers 		 * <type><device-name><unit> <pnpvars> \
349*7a0c41d5SAlan Somers 		 *                        at <location vars> <pnpvars> \
350*7a0c41d5SAlan Somers 		 *                        on <parent>
351*7a0c41d5SAlan Somers 		 *
352*7a0c41d5SAlan Somers 		 * Handle all data that doesn't conform to the
353*7a0c41d5SAlan Somers 		 * "name=value" format, and let the generic parser
354*7a0c41d5SAlan Somers 		 * below handle the rest.
355*7a0c41d5SAlan Somers 		 *
356*7a0c41d5SAlan Somers 		 * Type is a single char.  Skip it.
357*7a0c41d5SAlan Somers 		 */
358*7a0c41d5SAlan Somers 		start = 1;
359*7a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
360*7a0c41d5SAlan Somers 		if (end == string::npos)
361*7a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
362*7a0c41d5SAlan Somers 					     eventString, start);
363*7a0c41d5SAlan Somers 
364*7a0c41d5SAlan Somers 		nvpairs["device-name"] = eventString.substr(start, end - start);
365*7a0c41d5SAlan Somers 
366*7a0c41d5SAlan Somers 		start = eventString.find(" on ", end);
367*7a0c41d5SAlan Somers 		if (end == string::npos)
368*7a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
369*7a0c41d5SAlan Somers 					     eventString, start);
370*7a0c41d5SAlan Somers 		start += 4;
371*7a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
372*7a0c41d5SAlan Somers 		nvpairs["parent"] = eventString.substr(start, end);
373*7a0c41d5SAlan Somers 		break;
374*7a0c41d5SAlan Somers 	case NOTIFY:
375*7a0c41d5SAlan Somers 		break;
376*7a0c41d5SAlan Somers 	case NOMATCH:
377*7a0c41d5SAlan Somers 		throw ParseException(ParseException::DISCARDED_EVENT_TYPE,
378*7a0c41d5SAlan Somers 				     eventString);
379*7a0c41d5SAlan Somers 	default:
380*7a0c41d5SAlan Somers 		throw ParseException(ParseException::UNKNOWN_EVENT_TYPE,
381*7a0c41d5SAlan Somers 				     eventString);
382*7a0c41d5SAlan Somers 	}
383*7a0c41d5SAlan Somers 
384*7a0c41d5SAlan Somers 	/* Process common "key=value" format. */
385*7a0c41d5SAlan Somers 	for (start = 1; start < eventString.length(); start = end + 1) {
386*7a0c41d5SAlan Somers 
387*7a0c41d5SAlan Somers 		/* Find the '=' in the middle of the key/value pair. */
388*7a0c41d5SAlan Somers 		end = eventString.find('=', start);
389*7a0c41d5SAlan Somers 		if (end == string::npos)
390*7a0c41d5SAlan Somers 			break;
391*7a0c41d5SAlan Somers 
392*7a0c41d5SAlan Somers 		/*
393*7a0c41d5SAlan Somers 		 * Find the start of the key by backing up until
394*7a0c41d5SAlan Somers 		 * we hit whitespace or '!' (event type "notice").
395*7a0c41d5SAlan Somers 		 * Due to the devdctl format, all key/value pair must
396*7a0c41d5SAlan Somers 		 * start with one of these two characters.
397*7a0c41d5SAlan Somers 		 */
398*7a0c41d5SAlan Somers 		start = eventString.find_last_of("! \t\n", end);
399*7a0c41d5SAlan Somers 		if (start == string::npos)
400*7a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
401*7a0c41d5SAlan Somers 					     eventString, end);
402*7a0c41d5SAlan Somers 		start++;
403*7a0c41d5SAlan Somers 		string key(eventString.substr(start, end - start));
404*7a0c41d5SAlan Somers 
405*7a0c41d5SAlan Somers 		/*
406*7a0c41d5SAlan Somers 		 * Walk forward from the '=' until either we exhaust
407*7a0c41d5SAlan Somers 		 * the buffer or we hit whitespace.
408*7a0c41d5SAlan Somers 		 */
409*7a0c41d5SAlan Somers 		start = end + 1;
410*7a0c41d5SAlan Somers 		if (start >= eventString.length())
411*7a0c41d5SAlan Somers 			throw ParseException(ParseException::INVALID_FORMAT,
412*7a0c41d5SAlan Somers 					     eventString, end);
413*7a0c41d5SAlan Somers 		end = eventString.find_first_of(" \t\n", start);
414*7a0c41d5SAlan Somers 		if (end == string::npos)
415*7a0c41d5SAlan Somers 			end = eventString.length() - 1;
416*7a0c41d5SAlan Somers 		string value(eventString.substr(start, end - start));
417*7a0c41d5SAlan Somers 
418*7a0c41d5SAlan Somers 		nvpairs[key] = value;
419*7a0c41d5SAlan Somers 	}
420*7a0c41d5SAlan Somers }
421*7a0c41d5SAlan Somers 
422*7a0c41d5SAlan Somers void
423*7a0c41d5SAlan Somers Event::TimestampEventString(std::string &eventString)
424*7a0c41d5SAlan Somers {
425*7a0c41d5SAlan Somers 	if (eventString.size() > 0) {
426*7a0c41d5SAlan Somers 		/*
427*7a0c41d5SAlan Somers 		 * Add a timestamp as the final field of the event if it is
428*7a0c41d5SAlan Somers 		 * not already present.
429*7a0c41d5SAlan Somers 		 */
430*7a0c41d5SAlan Somers 		if (eventString.find("timestamp=") == string::npos) {
431*7a0c41d5SAlan Somers 			const size_t bufsize = 32;	// Long enough for a 64-bit int
432*7a0c41d5SAlan Somers 			timeval now;
433*7a0c41d5SAlan Somers 			char timebuf[bufsize];
434*7a0c41d5SAlan Somers 
435*7a0c41d5SAlan Somers 			size_t eventEnd(eventString.find_last_not_of('\n') + 1);
436*7a0c41d5SAlan Somers 			if (gettimeofday(&now, NULL) != 0)
437*7a0c41d5SAlan Somers 				err(1, "gettimeofday");
438*7a0c41d5SAlan Somers 			snprintf(timebuf, bufsize, " timestamp=%"PRId64,
439*7a0c41d5SAlan Somers 				(int64_t) now.tv_sec);
440*7a0c41d5SAlan Somers 			eventString.insert(eventEnd, timebuf);
441*7a0c41d5SAlan Somers 		}
442*7a0c41d5SAlan Somers 	}
443*7a0c41d5SAlan Somers }
444*7a0c41d5SAlan Somers 
445*7a0c41d5SAlan Somers /*-------------------------------- DevfsEvent --------------------------------*/
446*7a0c41d5SAlan Somers //- DevfsEvent Static Public Methods -------------------------------------------
447*7a0c41d5SAlan Somers Event *
448*7a0c41d5SAlan Somers DevfsEvent::Builder(Event::Type type, NVPairMap &nvPairs,
449*7a0c41d5SAlan Somers 		    const string &eventString)
450*7a0c41d5SAlan Somers {
451*7a0c41d5SAlan Somers 	return (new DevfsEvent(type, nvPairs, eventString));
452*7a0c41d5SAlan Somers }
453*7a0c41d5SAlan Somers 
454*7a0c41d5SAlan Somers //- DevfsEvent Static Protected Methods ----------------------------------------
455*7a0c41d5SAlan Somers bool
456*7a0c41d5SAlan Somers DevfsEvent::IsWholeDev(const string &devName)
457*7a0c41d5SAlan Somers {
458*7a0c41d5SAlan Somers 	string::const_iterator i(devName.begin());
459*7a0c41d5SAlan Somers 
460*7a0c41d5SAlan Somers 	size_t start = devName.rfind('/');
461*7a0c41d5SAlan Somers 	if (start == string::npos) {
462*7a0c41d5SAlan Somers 		start = 0;
463*7a0c41d5SAlan Somers 	} else {
464*7a0c41d5SAlan Somers 		/* Just after the last '/'. */
465*7a0c41d5SAlan Somers 		start++;
466*7a0c41d5SAlan Somers 	}
467*7a0c41d5SAlan Somers 	i += start;
468*7a0c41d5SAlan Somers 
469*7a0c41d5SAlan Somers 	/* alpha prefix followed only by digits. */
470*7a0c41d5SAlan Somers 	for (; i < devName.end() && !isdigit(*i); i++)
471*7a0c41d5SAlan Somers 		;
472*7a0c41d5SAlan Somers 
473*7a0c41d5SAlan Somers 	if (i == devName.end())
474*7a0c41d5SAlan Somers 		return (false);
475*7a0c41d5SAlan Somers 
476*7a0c41d5SAlan Somers 	for (; i < devName.end() && isdigit(*i); i++)
477*7a0c41d5SAlan Somers 		;
478*7a0c41d5SAlan Somers 
479*7a0c41d5SAlan Somers 	return (i == devName.end());
480*7a0c41d5SAlan Somers }
481*7a0c41d5SAlan Somers 
482*7a0c41d5SAlan Somers //- DevfsEvent Virtual Public Methods ------------------------------------------
483*7a0c41d5SAlan Somers Event *
484*7a0c41d5SAlan Somers DevfsEvent::DeepCopy() const
485*7a0c41d5SAlan Somers {
486*7a0c41d5SAlan Somers 	return (new DevfsEvent(*this));
487*7a0c41d5SAlan Somers }
488*7a0c41d5SAlan Somers 
489*7a0c41d5SAlan Somers bool
490*7a0c41d5SAlan Somers DevfsEvent::Process() const
491*7a0c41d5SAlan Somers {
492*7a0c41d5SAlan Somers 	return (true);
493*7a0c41d5SAlan Somers }
494*7a0c41d5SAlan Somers 
495*7a0c41d5SAlan Somers //- DevfsEvent Public Methods --------------------------------------------------
496*7a0c41d5SAlan Somers bool
497*7a0c41d5SAlan Somers DevfsEvent::IsWholeDev() const
498*7a0c41d5SAlan Somers {
499*7a0c41d5SAlan Somers 	string devName;
500*7a0c41d5SAlan Somers 
501*7a0c41d5SAlan Somers 	return (DevName(devName) && IsDiskDev() && IsWholeDev(devName));
502*7a0c41d5SAlan Somers }
503*7a0c41d5SAlan Somers 
504*7a0c41d5SAlan Somers bool
505*7a0c41d5SAlan Somers DevfsEvent::DevName(std::string &name) const
506*7a0c41d5SAlan Somers {
507*7a0c41d5SAlan Somers 	if (Value("subsystem") != "CDEV")
508*7a0c41d5SAlan Somers 		return (false);
509*7a0c41d5SAlan Somers 
510*7a0c41d5SAlan Somers 	name = Value("cdev");
511*7a0c41d5SAlan Somers 	return (!name.empty());
512*7a0c41d5SAlan Somers }
513*7a0c41d5SAlan Somers 
514*7a0c41d5SAlan Somers //- DevfsEvent Protected Methods -----------------------------------------------
515*7a0c41d5SAlan Somers DevfsEvent::DevfsEvent(Event::Type type, NVPairMap &nvpairs,
516*7a0c41d5SAlan Somers 		       const string &eventString)
517*7a0c41d5SAlan Somers  : Event(type, nvpairs, eventString)
518*7a0c41d5SAlan Somers {
519*7a0c41d5SAlan Somers }
520*7a0c41d5SAlan Somers 
521*7a0c41d5SAlan Somers DevfsEvent::DevfsEvent(const DevfsEvent &src)
522*7a0c41d5SAlan Somers  : Event(src)
523*7a0c41d5SAlan Somers {
524*7a0c41d5SAlan Somers }
525*7a0c41d5SAlan Somers 
526*7a0c41d5SAlan Somers /*--------------------------------- GeomEvent --------------------------------*/
527*7a0c41d5SAlan Somers //- GeomEvent Static Public Methods --------------------------------------------
528*7a0c41d5SAlan Somers Event *
529*7a0c41d5SAlan Somers GeomEvent::Builder(Event::Type type, NVPairMap &nvpairs,
530*7a0c41d5SAlan Somers 		   const string &eventString)
531*7a0c41d5SAlan Somers {
532*7a0c41d5SAlan Somers 	return (new GeomEvent(type, nvpairs, eventString));
533*7a0c41d5SAlan Somers }
534*7a0c41d5SAlan Somers 
535*7a0c41d5SAlan Somers //- GeomEvent Virtual Public Methods -------------------------------------------
536*7a0c41d5SAlan Somers Event *
537*7a0c41d5SAlan Somers GeomEvent::DeepCopy() const
538*7a0c41d5SAlan Somers {
539*7a0c41d5SAlan Somers 	return (new GeomEvent(*this));
540*7a0c41d5SAlan Somers }
541*7a0c41d5SAlan Somers 
542*7a0c41d5SAlan Somers bool
543*7a0c41d5SAlan Somers GeomEvent::DevName(std::string &name) const
544*7a0c41d5SAlan Somers {
545*7a0c41d5SAlan Somers 	name = Value("devname");
546*7a0c41d5SAlan Somers 	return (!name.empty());
547*7a0c41d5SAlan Somers }
548*7a0c41d5SAlan Somers 
549*7a0c41d5SAlan Somers 
550*7a0c41d5SAlan Somers //- GeomEvent Protected Methods ------------------------------------------------
551*7a0c41d5SAlan Somers GeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs,
552*7a0c41d5SAlan Somers 		     const string &eventString)
553*7a0c41d5SAlan Somers  : Event(type, nvpairs, eventString),
554*7a0c41d5SAlan Somers    m_devname(Value("devname"))
555*7a0c41d5SAlan Somers {
556*7a0c41d5SAlan Somers }
557*7a0c41d5SAlan Somers 
558*7a0c41d5SAlan Somers GeomEvent::GeomEvent(const GeomEvent &src)
559*7a0c41d5SAlan Somers  : Event(src),
560*7a0c41d5SAlan Somers    m_devname(src.m_devname)
561*7a0c41d5SAlan Somers {
562*7a0c41d5SAlan Somers }
563*7a0c41d5SAlan Somers 
564*7a0c41d5SAlan Somers /*--------------------------------- ZfsEvent ---------------------------------*/
565*7a0c41d5SAlan Somers //- ZfsEvent Static Public Methods ---------------------------------------------
566*7a0c41d5SAlan Somers Event *
567*7a0c41d5SAlan Somers ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs,
568*7a0c41d5SAlan Somers 		  const string &eventString)
569*7a0c41d5SAlan Somers {
570*7a0c41d5SAlan Somers 	return (new ZfsEvent(type, nvpairs, eventString));
571*7a0c41d5SAlan Somers }
572*7a0c41d5SAlan Somers 
573*7a0c41d5SAlan Somers //- ZfsEvent Virtual Public Methods --------------------------------------------
574*7a0c41d5SAlan Somers Event *
575*7a0c41d5SAlan Somers ZfsEvent::DeepCopy() const
576*7a0c41d5SAlan Somers {
577*7a0c41d5SAlan Somers 	return (new ZfsEvent(*this));
578*7a0c41d5SAlan Somers }
579*7a0c41d5SAlan Somers 
580*7a0c41d5SAlan Somers bool
581*7a0c41d5SAlan Somers ZfsEvent::DevName(std::string &name) const
582*7a0c41d5SAlan Somers {
583*7a0c41d5SAlan Somers 	return (false);
584*7a0c41d5SAlan Somers }
585*7a0c41d5SAlan Somers 
586*7a0c41d5SAlan Somers //- ZfsEvent Protected Methods -------------------------------------------------
587*7a0c41d5SAlan Somers ZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs,
588*7a0c41d5SAlan Somers 		   const string &eventString)
589*7a0c41d5SAlan Somers  : Event(type, nvpairs, eventString),
590*7a0c41d5SAlan Somers    m_poolGUID(Guid(Value("pool_guid"))),
591*7a0c41d5SAlan Somers    m_vdevGUID(Guid(Value("vdev_guid")))
592*7a0c41d5SAlan Somers {
593*7a0c41d5SAlan Somers }
594*7a0c41d5SAlan Somers 
595*7a0c41d5SAlan Somers ZfsEvent::ZfsEvent(const ZfsEvent &src)
596*7a0c41d5SAlan Somers  : Event(src),
597*7a0c41d5SAlan Somers    m_poolGUID(src.m_poolGUID),
598*7a0c41d5SAlan Somers    m_vdevGUID(src.m_vdevGUID)
599*7a0c41d5SAlan Somers {
600*7a0c41d5SAlan Somers }
601*7a0c41d5SAlan Somers 
602*7a0c41d5SAlan Somers } // namespace DevdCtl
603