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