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