1442baa5asomers/*-
2442baa5asomers * Copyright (c) 2011, 2012, 2013, 2016 Spectra Logic Corporation
3442baa5asomers * All rights reserved.
4442baa5asomers *
5442baa5asomers * Redistribution and use in source and binary forms, with or without
6442baa5asomers * modification, are permitted provided that the following conditions
7442baa5asomers * are met:
8442baa5asomers * 1. Redistributions of source code must retain the above copyright
9442baa5asomers *    notice, this list of conditions, and the following disclaimer,
10442baa5asomers *    without modification.
11442baa5asomers * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12442baa5asomers *    substantially similar to the "NO WARRANTY" disclaimer below
13442baa5asomers *    ("Disclaimer") and any redistribution must be conditioned upon
14442baa5asomers *    including a substantially similar Disclaimer requirement for further
15442baa5asomers *    binary redistribution.
16442baa5asomers *
17442baa5asomers * NO WARRANTY
18442baa5asomers * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19442baa5asomers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20442baa5asomers * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21442baa5asomers * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22442baa5asomers * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23442baa5asomers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24442baa5asomers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25442baa5asomers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26442baa5asomers * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27442baa5asomers * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28442baa5asomers * POSSIBILITY OF SUCH DAMAGES.
29442baa5asomers *
30442baa5asomers * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
31442baa5asomers */
32442baa5asomers
33442baa5asomers/**
34442baa5asomers * \file event.cc
35442baa5asomers *
36442baa5asomers * Implementation of the class hierarchy used to express events
37442baa5asomers * received via the devdctl API.
38442baa5asomers */
39442baa5asomers#include <sys/cdefs.h>
40442baa5asomers#include <sys/disk.h>
41442baa5asomers#include <sys/filio.h>
42442baa5asomers#include <sys/param.h>
43442baa5asomers#include <sys/stat.h>
44442baa5asomers
45442baa5asomers#include <err.h>
46442baa5asomers#include <fcntl.h>
47442baa5asomers#include <inttypes.h>
48442baa5asomers#include <paths.h>
49442baa5asomers#include <stdlib.h>
50442baa5asomers#include <syslog.h>
51442baa5asomers#include <unistd.h>
52442baa5asomers
53442baa5asomers#include <cstdarg>
54442baa5asomers#include <cstring>
55442baa5asomers#include <iostream>
56442baa5asomers#include <list>
57442baa5asomers#include <map>
58442baa5asomers#include <sstream>
59442baa5asomers#include <string>
60442baa5asomers
61442baa5asomers#include "guid.h"
62442baa5asomers#include "event.h"
63442baa5asomers#include "event_factory.h"
64442baa5asomers#include "exception.h"
65442baa5asomers
66442baa5asomers__FBSDID("$FreeBSD$");
67442baa5asomers
68442baa5asomers/*================================== Macros ==================================*/
69442baa5asomers#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x))
70442baa5asomers
71442baa5asomers/*============================ Namespace Control =============================*/
72442baa5asomersusing std::cout;
73442baa5asomersusing std::endl;
74442baa5asomersusing std::string;
75442baa5asomersusing std::stringstream;
76442baa5asomers
77442baa5asomersnamespace DevdCtl
78442baa5asomers{
79442baa5asomers
80442baa5asomers/*=========================== Class Implementations ==========================*/
81442baa5asomers/*----------------------------------- Event ----------------------------------*/
82442baa5asomers//- Event Static Protected Data ------------------------------------------------
83442baa5asomersconst string Event::s_theEmptyString;
84442baa5asomers
85442baa5asomersEvent::EventTypeRecord Event::s_typeTable[] =
86442baa5asomers{
87442baa5asomers	{ Event::NOTIFY,  "Notify" },
88442baa5asomers	{ Event::NOMATCH, "No Driver Match" },
89442baa5asomers	{ Event::ATTACH,  "Attach" },
90442baa5asomers	{ Event::DETACH,  "Detach" }
91442baa5asomers};
92442baa5asomers
93442baa5asomers//- Event Static Public Methods ------------------------------------------------
94442baa5asomersEvent *
95442baa5asomersEvent::Builder(Event::Type type, NVPairMap &nvPairs,
96442baa5asomers	       const string &eventString)
97442baa5asomers{
98442baa5asomers	return (new Event(type, nvPairs, eventString));
99442baa5asomers}
100442baa5asomers
101442baa5asomersEvent *
102442baa5asomersEvent::CreateEvent(const EventFactory &factory, const string &eventString)
103442baa5asomers{
104442baa5asomers	NVPairMap &nvpairs(*new NVPairMap);
105442baa5asomers	Type       type(static_cast<Event::Type>(eventString[0]));
106442baa5asomers
107442baa5asomers	try {
108442baa5asomers		ParseEventString(type, eventString, nvpairs);
109442baa5asomers	} catch (const ParseException &exp) {
110442baa5asomers		if (exp.GetType() == ParseException::INVALID_FORMAT)
111442baa5asomers			exp.Log();
112442baa5asomers		return (NULL);
113442baa5asomers	}
114442baa5asomers
115442baa5asomers	/*
116442baa5asomers	 * Allow entries in our table for events with no system specified.
117442baa5asomers	 * These entries should specify the string "none".
118442baa5asomers	 */
119442baa5asomers	NVPairMap::iterator system_item(nvpairs.find("system"));
120442baa5asomers	if (system_item == nvpairs.end())
121442baa5asomers		nvpairs["system"] = "none";
122442baa5asomers
123442baa5asomers	return (factory.Build(type, nvpairs, eventString));
124442baa5asomers}
125442baa5asomers
126442baa5asomersbool
127442baa5asomersEvent::DevName(std::string &name) const
128442baa5asomers{
129442baa5asomers	return (false);
130442baa5asomers}
131442baa5asomers
132442baa5asomers/* TODO: simplify this function with C++-11 <regex> methods */
133442baa5asomersbool
134442baa5asomersEvent::IsDiskDev() const
135442baa5asomers{
136442baa5asomers	const int numDrivers = 2;
137442baa5asomers	static const char *diskDevNames[numDrivers] =
138442baa5asomers	{
139442baa5asomers		"da",
140442baa5asomers		"ada"
141442baa5asomers	};
142442baa5asomers	const char **dName;
143442baa5asomers	string devName;
144442baa5asomers
145442baa5asomers	if (! DevName(devName))
146442baa5asomers		return false;
147442baa5asomers
148442baa5asomers	size_t find_start = devName.rfind('/');
149442baa5asomers	if (find_start == string::npos) {
150442baa5asomers		find_start = 0;
151442baa5asomers	} else {
152442baa5asomers		/* Just after the last '/'. */
153442baa5asomers		find_start++;
154442baa5asomers	}
155442baa5asomers
156442baa5asomers	for (dName = &diskDevNames[0];
157442baa5asomers	     dName <= &diskDevNames[numDrivers - 1]; dName++) {
158442baa5asomers
159442baa5asomers		size_t loc(devName.find(*dName, find_start));
160442baa5asomers		if (loc == find_start) {
161442baa5asomers			size_t prefixLen(strlen(*dName));
162442baa5asomers
163442baa5asomers			if (devName.length() - find_start >= prefixLen
164442baa5asomers			 && isdigit(devName[find_start + prefixLen]))
165442baa5asomers				return (true);
166442baa5asomers		}
167442baa5asomers	}
168442baa5asomers
169442baa5asomers	return (false);
170442baa5asomers}
171442baa5asomers
172442baa5asomersconst char *
173442baa5asomersEvent::TypeToString(Event::Type type)
174442baa5asomers{
175442baa5asomers	EventTypeRecord *rec(s_typeTable);
176