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 =============================*/
44 namespace DevdCtl
45 {
46
47 /*=========================== Forward Declarations ===========================*/
48 class EventFactory;
49
50 /*============================= Class Definitions ============================*/
51 /*-------------------------------- NVPairMap ---------------------------------*/
52 /**
53 * NVPairMap is a specialization of the standard map STL container.
54 */
55 typedef 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 */
68 class Event
69 {
70 friend class EventFactory;
71
72 public:
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
235 protected:
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
278 private:
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
289 inline Event::Type
GetType()290 Event::GetType() const
291 {
292 return (m_type);
293 }
294
295 inline const std::string &
GetEventString()296 Event::GetEventString() const
297 {
298 return (m_eventString);
299 }
300
301 inline const NVPairMap &
GetMap()302 Event::GetMap() const
303 {
304 return (m_nvPairs);
305 }
306
307 /*--------------------------------- EventList --------------------------------*/
308 /**
309 * EventList is a specialization of the standard list STL container.
310 */
311 typedef std::list<Event *> EventList;
312
313 /*-------------------------------- DevfsEvent --------------------------------*/
314 class DevfsEvent : public Event
315 {
316 public:
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
332 protected:
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 --------------------------------*/
352 class GeomEvent : public Event
353 {
354 public:
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
364 protected:
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 ---------------------------------*/
375 class ZfsEvent : public Event
376 {
377 public:
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
389 protected:
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 --------------------------------------------
401 inline const std::string&
PoolName()402 ZfsEvent::PoolName() const
403 {
404 /* The pool name is reported as the subsystem of ZFS events. */
405 return (Value("subsystem"));
406 }
407
408 inline Guid
PoolGUID()409 ZfsEvent::PoolGUID() const
410 {
411 return (m_poolGUID);
412 }
413
414 inline Guid
VdevGUID()415 ZfsEvent::VdevGUID() const
416 {
417 return (m_vdevGUID);
418 }
419
420 } // namespace DevdCtl
421 #endif /*_DEVDCTL_EVENT_H_ */
422