1/*-
2 * Copyright (c) 2011, 2012, 2013, 2016 Spectra Logic Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions, and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    substantially similar to the "NO WARRANTY" disclaimer below
13 *    ("Disclaimer") and any redistribution must be conditioned upon
14 *    including a substantially similar Disclaimer requirement for further
15 *    binary redistribution.
16 *
17 * NO WARRANTY
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGES.
29 *
30 * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
31 *
32 * $FreeBSD$
33 */
34
35/**
36 * \file devdctl_event.h
37 *
38 * \brief Class hierarchy used to express events received via
39 *        the devdctl API.
40 */
41
42#ifndef _DEVDCTL_EVENT_H_
43#define	_DEVDCTL_EVENT_H_
44
45/*============================ Namespace Control =============================*/
46namespace DevdCtl
47{
48
49/*=========================== Forward Declarations ===========================*/
50class EventFactory;
51
52/*============================= Class Definitions ============================*/
53/*-------------------------------- NVPairMap ---------------------------------*/
54/**
55 * NVPairMap is a specialization of the standard map STL container.
56 */
57typedef std::map<std::string, std::string> NVPairMap;
58
59/*----------------------------------- Event ----------------------------------*/
60/**
61 * \brief Container for the name => value pairs that comprise the content of
62 *        a device control event.
63 *
64 * All name => value data for events can be accessed via the Contains()
65 * and Value() methods.  name => value pairs for data not explicitly
66 * received as a name => value pair are synthesized during parsing.  For
67 * example, ATTACH and DETACH events have "device-name" and "parent"
68 * name => value pairs added.
69 */
70class Event
71{
72	friend class EventFactory;
73
74public:
75	/** Event type */
76	enum Type {
77		/** Generic event notification. */
78		NOTIFY  = '!',
79
80		/** A driver was not found for this device. */
81		NOMATCH = '?',
82
83		/** A bus device instance has been added. */
84		ATTACH  = '+',
85
86		/** A bus device instance has been removed. */
87		DETACH  = '-'
88	};
89
90	/**
91	 * Factory method type to construct an Event given
92	 * the type of event and an NVPairMap populated from
93	 * the event string received from devd.
94	 */
95	typedef Event* (BuildMethod)(Type, NVPairMap &, const std::string &);
96
97	/** Generic Event object factory. */
98	static BuildMethod Builder;
99
100	static Event *CreateEvent(const EventFactory &factory,
101				  const std::string &eventString);
102
103	/**
104	 * Returns the devname, if any, associated with the event
105	 *
106	 * \param name	Devname, returned by reference
107	 * \return	True iff the event contained a devname
108	 */
109	virtual bool DevName(std::string &name)	const;
110
111	/**
112	 * Returns the absolute pathname of the device associated with this
113	 * event.
114	 *
115	 * \param name	Devname, returned by reference
116	 * \return	True iff the event contained a devname
117	 */
118	bool DevPath(std::string &path)		const;
119
120	/**
121	 * Returns true iff this event refers to a disk device
122	 */
123	bool IsDiskDev()			const;
124
125	/** Returns the physical path of the device, if any
126	 *
127	 * \param path	Physical path, returned by reference
128	 * \return	True iff the event contains a device with a physical
129	 * 		path
130	 */
131	bool PhysicalPath(std::string &path)	const;
132
133	/**
134	 * Provide a user friendly string representation of an
135	 * event type.
136	 *
137	 * \param type  The type of event to map to a string.
138	 *
139	 * \return  A user friendly string representing the input type.
140	 */
141	static const char  *TypeToString(Type type);
142
143	/**
144	 * Determine the availability of a name => value pair by name.
145	 *
146	 * \param name  The key name to search for in this event instance.
147	 *
148	 * \return  true if the specified key is available in this
149	 *          event, otherwise false.
150	 */
151	bool Contains(const std::string &name)		 const;
152
153	/**
154	 * \param key  The name of the key for which to retrieve its
155	 *             associated value.
156	 *
157	 * \return  A const reference to the string representing the
158	 *          value associated with key.
159	 *
160	 * \note  For key's with no registered value, the empty string
161	 *        is returned.
162	 */
163	const std::string &Value(const std::string &key) const;
164
165	/**
166	 * Get the type of this event instance.
167	 *
168	 * \return  The type of this event instance.
169	 */
170	Type GetType()					 const;
171
172	/**
173	 * Get the original DevdCtl event string for this event.
174	 *
175	 * \return  The DevdCtl event string.
176	 */
177	const std::string &GetEventString()		 const;
178
179	/**
180	 * Convert the event instance into a string suitable for
181	 * printing to the console or emitting to syslog.
182	 *
183	 * \return  A string of formatted event data.
184	 */
185	std::string ToString()				 const;
186
187	/**
188	 * Pretty-print this event instance to cout.
189	 */
190	void Print()					 const;
191
192	/**
193	 * Pretty-print this event instance to syslog.
194	 *
195	 * \param priority  The logging priority/facility.
196	 *                  See syslog(3).
197	 */
198	void Log(int priority)				 const;
199
200	/**
201	 * Create and return a fully independent clone
202	 * of this event.
203	 */
204	virtual Event *DeepCopy()			 const;
205
206	/** Destructor */
207	virtual ~Event();
208
209	/**
210	 * Interpret and perform any actions necessary to
211	 * consume the event.
212	 *
213	 * \return True if this event should be queued for later reevaluation
214	 */
215	virtual bool Process()				 const;
216
217	/**
218	 * Get the time that the event was created
219	 */
220	timeval GetTimestamp()				 const;
221
222	/**
223	 * Add a timestamp to the event string, if one does not already exist
224	 * TODO: make this an instance method that operates on the std::map
225	 * instead of the string.  We must fix zfsd's CaseFile serialization
226	 * routines first, so that they don't need the raw event string.
227	 *
228	 * \param[in,out] eventString The devd event string to modify
229	 */
230	static void TimestampEventString(std::string &eventString);
231
232	/**
233	 * Access all parsed key => value pairs.
234	 */
235	const NVPairMap &GetMap()			 const;
236
237protected:
238	/** Table entries used to map a type to a user friendly string. */
239	struct EventTypeRecord
240	{
241		Type         m_type;
242		const char  *m_typeName;
243	};
244
245	/**
246	 * Constructor
247	 *
248	 * \param type  The type of event to create.
249	 */
250	Event(Type type, NVPairMap &map, const std::string &eventString);
251
252	/** Deep copy constructor. */
253	Event(const Event &src);
254
255	/** Always empty string returned when NVPairMap lookups fail. */
256	static const std::string    s_theEmptyString;
257
258	/** Unsorted table of event types. */
259	static EventTypeRecord      s_typeTable[];
260
261	/** The type of this event. */
262	const Type                  m_type;
263
264	/**
265	 * Event attribute storage.
266	 *
267	 * \note Although stored by reference (since m_nvPairs can
268	 *       never be NULL), the NVPairMap referenced by this field
269	 *       is dynamically allocated and owned by this event object.
270	 *       m_nvPairs must be deleted at event destruction.
271	 */
272	NVPairMap                  &m_nvPairs;
273
274	/**
275	 * The unaltered event string, as received from devd, used to
276	 * create this event object.
277	 */
278	std::string                 m_eventString;
279
280private:
281	/**
282	 * Ingest event data from the supplied string.
283	 *
284	 * \param[in] eventString  The string of devd event data to parse.
285	 * \param[out] nvpairs     Returns the parsed data
286	 */
287	static void ParseEventString(Type type, const std::string &eventString,
288				     NVPairMap &nvpairs);
289};
290
291inline Event::Type
292Event::GetType() const
293{
294	return (m_type);
295}
296
297inline const std::string &
298Event::GetEventString() const
299{
300	return (m_eventString);
301}
302
303inline const NVPairMap &
304Event::GetMap()	const
305{
306	return (m_nvPairs);
307}
308
309/*--------------------------------- EventList --------------------------------*/
310/**
311 * EventList is a specialization of the standard list STL container.
312 */
313typedef std::list<Event *> EventList;
314
315/*-------------------------------- DevfsEvent --------------------------------*/
316class DevfsEvent : public Event
317{
318public:
319	/** Specialized Event object factory for Devfs events. */
320	static BuildMethod Builder;
321
322	virtual Event *DeepCopy()		const;
323
324	/**
325	 * Interpret and perform any actions necessary to
326	 * consume the event.
327	 * \return True if this event should be queued for later reevaluation
328	 */
329	virtual bool Process()			const;
330
331	bool IsWholeDev()			const;
332	virtual bool DevName(std::string &name)	const;
333
334protected:
335	/**
336	 * Given the device name of a disk, determine if the device
337	 * represents the whole device, not just a partition.
338	 *
339	 * \param devName  Device name of disk device to test.
340	 *
341	 * \return  True if the device name represents the whole device.
342	 *          Otherwise false.
343	 */
344	static bool IsWholeDev(const std::string &devName);
345
346	/** DeepCopy Constructor. */
347	DevfsEvent(const DevfsEvent &src);
348
349	/** Constructor */
350	DevfsEvent(Type, NVPairMap &, const std::string &);
351};
352
353/*--------------------------------- GeomEvent --------------------------------*/
354class GeomEvent : public Event
355{
356public:
357	/** Specialized Event object factory for GEOM events. */
358	static BuildMethod Builder;
359
360	virtual Event *DeepCopy()	const;
361
362	virtual bool DevName(std::string &name)	const;
363
364	const std::string &DeviceName()	const;
365
366protected:
367	/** Constructor */
368	GeomEvent(Type, NVPairMap &, const std::string &);
369
370	/** Deep copy constructor. */
371	GeomEvent(const GeomEvent &src);
372
373	std::string m_devname;
374};
375
376/*--------------------------------- ZfsEvent ---------------------------------*/
377class ZfsEvent : public Event
378{
379public:
380	/** Specialized Event object factory for ZFS events. */
381	static BuildMethod Builder;
382
383	virtual Event *DeepCopy()	const;
384
385	virtual bool DevName(std::string &name)	const;
386
387	const std::string &PoolName()	const;
388	Guid		   PoolGUID()	const;
389	Guid		   VdevGUID()	const;
390
391protected:
392	/** Constructor */
393	ZfsEvent(Type, NVPairMap &, const std::string &);
394
395	/** Deep copy constructor. */
396	ZfsEvent(const ZfsEvent &src);
397
398	Guid	m_poolGUID;
399	Guid	m_vdevGUID;
400};
401
402//- ZfsEvent Inline Public Methods --------------------------------------------
403inline const std::string&
404ZfsEvent::PoolName() const
405{
406	/* The pool name is reported as the subsystem of ZFS events. */
407	return (Value("subsystem"));
408}
409
410inline Guid
411ZfsEvent::PoolGUID() const
412{
413	return (m_poolGUID);
414}
415
416inline Guid
417ZfsEvent::VdevGUID() const
418{
419	return (m_vdevGUID);
420}
421
422} // namespace DevdCtl
423#endif /*_DEVDCTL_EVENT_H_ */
424