1*7a0c41d5SAlan Somers /*- 2*7a0c41d5SAlan Somers * Copyright (c) 2011, 2012, 2013, 2016 Spectra Logic Corporation 3*7a0c41d5SAlan Somers * All rights reserved. 4*7a0c41d5SAlan Somers * 5*7a0c41d5SAlan Somers * Redistribution and use in source and binary forms, with or without 6*7a0c41d5SAlan Somers * modification, are permitted provided that the following conditions 7*7a0c41d5SAlan Somers * are met: 8*7a0c41d5SAlan Somers * 1. Redistributions of source code must retain the above copyright 9*7a0c41d5SAlan Somers * notice, this list of conditions, and the following disclaimer, 10*7a0c41d5SAlan Somers * without modification. 11*7a0c41d5SAlan Somers * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12*7a0c41d5SAlan Somers * substantially similar to the "NO WARRANTY" disclaimer below 13*7a0c41d5SAlan Somers * ("Disclaimer") and any redistribution must be conditioned upon 14*7a0c41d5SAlan Somers * including a substantially similar Disclaimer requirement for further 15*7a0c41d5SAlan Somers * binary redistribution. 16*7a0c41d5SAlan Somers * 17*7a0c41d5SAlan Somers * NO WARRANTY 18*7a0c41d5SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19*7a0c41d5SAlan Somers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20*7a0c41d5SAlan Somers * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21*7a0c41d5SAlan Somers * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22*7a0c41d5SAlan Somers * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*7a0c41d5SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*7a0c41d5SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*7a0c41d5SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26*7a0c41d5SAlan Somers * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27*7a0c41d5SAlan Somers * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*7a0c41d5SAlan Somers * POSSIBILITY OF SUCH DAMAGES. 29*7a0c41d5SAlan Somers * 30*7a0c41d5SAlan Somers * Authors: Justin T. Gibbs (Spectra Logic Corporation) 31*7a0c41d5SAlan Somers */ 32*7a0c41d5SAlan Somers 33*7a0c41d5SAlan Somers /** 34*7a0c41d5SAlan Somers * \file event.cc 35*7a0c41d5SAlan Somers * 36*7a0c41d5SAlan Somers * Implementation of the class hierarchy used to express events 37*7a0c41d5SAlan Somers * received via the devdctl API. 38*7a0c41d5SAlan Somers */ 39*7a0c41d5SAlan Somers #include <sys/cdefs.h> 40*7a0c41d5SAlan Somers #include <sys/disk.h> 41*7a0c41d5SAlan Somers #include <sys/filio.h> 42*7a0c41d5SAlan Somers #include <sys/param.h> 43*7a0c41d5SAlan Somers #include <sys/stat.h> 44*7a0c41d5SAlan Somers 45*7a0c41d5SAlan Somers #include <err.h> 46*7a0c41d5SAlan Somers #include <fcntl.h> 47*7a0c41d5SAlan Somers #include <inttypes.h> 48*7a0c41d5SAlan Somers #include <paths.h> 49*7a0c41d5SAlan Somers #include <stdlib.h> 50*7a0c41d5SAlan Somers #include <syslog.h> 51*7a0c41d5SAlan Somers #include <unistd.h> 52*7a0c41d5SAlan Somers 53*7a0c41d5SAlan Somers #include <cstdarg> 54*7a0c41d5SAlan Somers #include <cstring> 55*7a0c41d5SAlan Somers #include <iostream> 56*7a0c41d5SAlan Somers #include <list> 57*7a0c41d5SAlan Somers #include <map> 58*7a0c41d5SAlan Somers #include <sstream> 59*7a0c41d5SAlan Somers #include <string> 60*7a0c41d5SAlan Somers 61*7a0c41d5SAlan Somers #include "guid.h" 62*7a0c41d5SAlan Somers #include "event.h" 63*7a0c41d5SAlan Somers #include "event_factory.h" 64*7a0c41d5SAlan Somers #include "exception.h" 65*7a0c41d5SAlan Somers 66*7a0c41d5SAlan Somers __FBSDID("$FreeBSD$"); 67*7a0c41d5SAlan Somers 68*7a0c41d5SAlan Somers /*================================== Macros ==================================*/ 69*7a0c41d5SAlan Somers #define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) 70*7a0c41d5SAlan Somers 71*7a0c41d5SAlan Somers /*============================ Namespace Control =============================*/ 72*7a0c41d5SAlan Somers using std::cout; 73*7a0c41d5SAlan Somers using std::endl; 74*7a0c41d5SAlan Somers using std::string; 75*7a0c41d5SAlan Somers using std::stringstream; 76*7a0c41d5SAlan Somers 77*7a0c41d5SAlan Somers namespace DevdCtl 78*7a0c41d5SAlan Somers { 79*7a0c41d5SAlan Somers 80*7a0c41d5SAlan Somers /*=========================== Class Implementations ==========================*/ 81*7a0c41d5SAlan Somers /*----------------------------------- Event ----------------------------------*/ 82*7a0c41d5SAlan Somers //- Event Static Protected Data ------------------------------------------------ 83*7a0c41d5SAlan Somers const string Event::s_theEmptyString; 84*7a0c41d5SAlan Somers 85*7a0c41d5SAlan Somers Event::EventTypeRecord Event::s_typeTable[] = 86*7a0c41d5SAlan Somers { 87*7a0c41d5SAlan Somers { Event::NOTIFY, "Notify" }, 88*7a0c41d5SAlan Somers { Event::NOMATCH, "No Driver Match" }, 89*7a0c41d5SAlan Somers { Event::ATTACH, "Attach" }, 90*7a0c41d5SAlan Somers { Event::DETACH, "Detach" } 91*7a0c41d5SAlan Somers }; 92*7a0c41d5SAlan Somers 93*7a0c41d5SAlan Somers //- Event Static Public Methods ------------------------------------------------ 94*7a0c41d5SAlan Somers Event * 95*7a0c41d5SAlan Somers Event::Builder(Event::Type type, NVPairMap &nvPairs, 96*7a0c41d5SAlan Somers const string &eventString) 97*7a0c41d5SAlan Somers { 98*7a0c41d5SAlan Somers return (new Event(type, nvPairs, eventString)); 99*7a0c41d5SAlan Somers } 100*7a0c41d5SAlan Somers 101*7a0c41d5SAlan Somers Event * 102*7a0c41d5SAlan Somers Event::CreateEvent(const EventFactory &factory, const string &eventString) 103*7a0c41d5SAlan Somers { 104*7a0c41d5SAlan Somers NVPairMap &nvpairs(*new NVPairMap); 105*7a0c41d5SAlan Somers Type type(static_cast<Event::Type>(eventString[0])); 106*7a0c41d5SAlan Somers 107*7a0c41d5SAlan Somers try { 108*7a0c41d5SAlan Somers ParseEventString(type, eventString, nvpairs); 109*7a0c41d5SAlan Somers } catch (const ParseException &exp) { 110*7a0c41d5SAlan Somers if (exp.GetType() == ParseException::INVALID_FORMAT) 111*7a0c41d5SAlan Somers exp.Log(); 112*7a0c41d5SAlan Somers return (NULL); 113*7a0c41d5SAlan Somers } 114*7a0c41d5SAlan Somers 115*7a0c41d5SAlan Somers /* 116*7a0c41d5SAlan Somers * Allow entries in our table for events with no system specified. 117*7a0c41d5SAlan Somers * These entries should specify the string "none". 118*7a0c41d5SAlan Somers */ 119*7a0c41d5SAlan Somers NVPairMap::iterator system_item(nvpairs.find("system")); 120*7a0c41d5SAlan Somers if (system_item == nvpairs.end()) 121*7a0c41d5SAlan Somers nvpairs["system"] = "none"; 122*7a0c41d5SAlan Somers 123*7a0c41d5SAlan Somers return (factory.Build(type, nvpairs, eventString)); 124*7a0c41d5SAlan Somers } 125*7a0c41d5SAlan Somers 126*7a0c41d5SAlan Somers bool 127*7a0c41d5SAlan Somers Event::DevName(std::string &name) const 128*7a0c41d5SAlan Somers { 129*7a0c41d5SAlan Somers return (false); 130*7a0c41d5SAlan Somers } 131*7a0c41d5SAlan Somers 132*7a0c41d5SAlan Somers /* TODO: simplify this function with C++-11 <regex> methods */ 133*7a0c41d5SAlan Somers bool 134*7a0c41d5SAlan Somers Event::IsDiskDev() const 135*7a0c41d5SAlan Somers { 136*7a0c41d5SAlan Somers const int numDrivers = 2; 137*7a0c41d5SAlan Somers static const char *diskDevNames[numDrivers] = 138*7a0c41d5SAlan Somers { 139*7a0c41d5SAlan Somers "da", 140*7a0c41d5SAlan Somers "ada" 141*7a0c41d5SAlan Somers }; 142*7a0c41d5SAlan Somers const char **dName; 143*7a0c41d5SAlan Somers string devName; 144*7a0c41d5SAlan Somers 145*7a0c41d5SAlan Somers if (! DevName(devName)) 146*7a0c41d5SAlan Somers return false; 147*7a0c41d5SAlan Somers 148*7a0c41d5SAlan Somers size_t find_start = devName.rfind('/'); 149*7a0c41d5SAlan Somers if (find_start == string::npos) { 150*7a0c41d5SAlan Somers find_start = 0; 151*7a0c41d5SAlan Somers } else { 152*7a0c41d5SAlan Somers /* Just after the last '/'. */ 153*7a0c41d5SAlan Somers find_start++; 154*7a0c41d5SAlan Somers } 155*7a0c41d5SAlan Somers 156*7a0c41d5SAlan Somers for (dName = &diskDevNames[0]; 157*7a0c41d5SAlan Somers dName <= &diskDevNames[numDrivers - 1]; dName++) { 158*7a0c41d5SAlan Somers 159*7a0c41d5SAlan Somers size_t loc(devName.find(*dName, find_start)); 160*7a0c41d5SAlan Somers if (loc == find_start) { 161*7a0c41d5SAlan Somers size_t prefixLen(strlen(*dName)); 162*7a0c41d5SAlan Somers 163*7a0c41d5SAlan Somers if (devName.length() - find_start >= prefixLen 164*7a0c41d5SAlan Somers && isdigit(devName[find_start + prefixLen])) 165*7a0c41d5SAlan Somers return (true); 166*7a0c41d5SAlan Somers } 167*7a0c41d5SAlan Somers } 168*7a0c41d5SAlan Somers 169*7a0c41d5SAlan Somers return (false); 170*7a0c41d5SAlan Somers } 171*7a0c41d5SAlan Somers 172*7a0c41d5SAlan Somers const char * 173*7a0c41d5SAlan Somers Event::TypeToString(Event::Type type) 174*7a0c41d5SAlan Somers { 175*7a0c41d5SAlan Somers EventTypeRecord *rec(s_typeTable); 176*7a0c41d5SAlan Somers EventTypeRecord *lastRec(s_typeTable + NUM_ELEMENTS(s_typeTable) - 1); 177*7a0c41d5SAlan Somers 178*7a0c41d5SAlan Somers for (; rec <= lastRec; rec++) { 179*7a0c41d5SAlan Somers if (rec->m_type == type) 180*7a0c41d5SAlan Somers return (rec->m_typeName); 181*7a0c41d5SAlan Somers } 182*7a0c41d5SAlan Somers return ("Unknown"); 183*7a0c41d5SAlan Somers } 184*7a0c41d5SAlan Somers 185*7a0c41d5SAlan Somers //- Event Public Methods ------------------------------------------------------- 186*7a0c41d5SAlan Somers const string & 187*7a0c41d5SAlan Somers Event::Value(const string &varName) const 188*7a0c41d5SAlan Somers { 189*7a0c41d5SAlan Somers NVPairMap::const_iterator item(m_nvPairs.find(varName)); 190*7a0c41d5SAlan Somers if (item == m_nvPairs.end()) 191*7a0c41d5SAlan Somers return (s_theEmptyString); 192*7a0c41d5SAlan Somers 193*7a0c41d5SAlan Somers return (item->second); 194*7a0c41d5SAlan Somers } 195*7a0c41d5SAlan Somers 196*7a0c41d5SAlan Somers bool 197*7a0c41d5SAlan Somers Event::Contains(const string &varName) const 198*7a0c41d5SAlan Somers { 199*7a0c41d5SAlan Somers return (m_nvPairs.find(varName) != m_nvPairs.end()); 200*7a0c41d5SAlan Somers } 201*7a0c41d5SAlan Somers 202*7a0c41d5SAlan Somers string 203*7a0c41d5SAlan Somers Event::ToString() const 204*7a0c41d5SAlan Somers { 205*7a0c41d5SAlan Somers stringstream result; 206*7a0c41d5SAlan Somers 207*7a0c41d5SAlan Somers NVPairMap::const_iterator devName(m_nvPairs.find("device-name")); 208*7a0c41d5SAlan Somers if (devName != m_nvPairs.end()) 209*7a0c41d5SAlan Somers result << devName->second << ": "; 210*7a0c41d5SAlan Somers 211*7a0c41d5SAlan Somers NVPairMap::const_iterator systemName(m_nvPairs.find("system")); 212*7a0c41d5SAlan Somers if (systemName != m_nvPairs.end() 213*7a0c41d5SAlan Somers && systemName->second != "none") 214*7a0c41d5SAlan Somers result << systemName->second << ": "; 215*7a0c41d5SAlan Somers 216*7a0c41d5SAlan Somers result << TypeToString(GetType()) << ' '; 217*7a0c41d5SAlan Somers 218*7a0c41d5SAlan Somers for (NVPairMap::const_iterator curVar = m_nvPairs.begin(); 219*7a0c41d5SAlan Somers curVar != m_nvPairs.end(); curVar++) { 220*7a0c41d5SAlan Somers if (curVar == devName || curVar == systemName) 221*7a0c41d5SAlan Somers continue; 222*7a0c41d5SAlan Somers 223*7a0c41d5SAlan Somers result << ' ' 224*7a0c41d5SAlan Somers << curVar->first << "=" << curVar->second; 225*7a0c41d5SAlan Somers } 226*7a0c41d5SAlan Somers result << endl; 227*7a0c41d5SAlan Somers 228*7a0c41d5SAlan Somers return (result.str()); 229*7a0c41d5SAlan Somers } 230*7a0c41d5SAlan Somers 231*7a0c41d5SAlan Somers void 232*7a0c41d5SAlan Somers Event::Print() const 233*7a0c41d5SAlan Somers { 234*7a0c41d5SAlan Somers cout << ToString() << std::flush; 235*7a0c41d5SAlan Somers } 236*7a0c41d5SAlan Somers 237*7a0c41d5SAlan Somers void 238*7a0c41d5SAlan Somers Event::Log(int priority) const 239*7a0c41d5SAlan Somers { 240*7a0c41d5SAlan Somers syslog(priority, "%s", ToString().c_str()); 241*7a0c41d5SAlan Somers } 242*7a0c41d5SAlan Somers 243*7a0c41d5SAlan Somers //- Event Virtual Public Methods ----------------------------------------------- 244*7a0c41d5SAlan Somers Event::~Event() 245*7a0c41d5SAlan Somers { 246*7a0c41d5SAlan Somers delete &m_nvPairs; 247*7a0c41d5SAlan Somers } 248*7a0c41d5SAlan Somers 249*7a0c41d5SAlan Somers Event * 250*7a0c41d5SAlan Somers Event::DeepCopy() const 251*7a0c41d5SAlan Somers { 252*7a0c41d5SAlan Somers return (new Event(*this)); 253*7a0c41d5SAlan Somers } 254*7a0c41d5SAlan Somers 255*7a0c41d5SAlan Somers bool 256*7a0c41d5SAlan Somers Event::Process() const 257*7a0c41d5SAlan Somers { 258*7a0c41d5SAlan Somers return (false); 259*7a0c41d5SAlan Somers } 260*7a0c41d5SAlan Somers 261*7a0c41d5SAlan Somers timeval 262*7a0c41d5SAlan Somers Event::GetTimestamp() const 263*7a0c41d5SAlan Somers { 264*7a0c41d5SAlan Somers timeval tv_timestamp; 265*7a0c41d5SAlan Somers struct tm tm_timestamp; 266*7a0c41d5SAlan Somers 267*7a0c41d5SAlan Somers if (!Contains("timestamp")) { 268*7a0c41d5SAlan Somers throw Exception("Event contains no timestamp: %s", 269*7a0c41d5SAlan Somers m_eventString.c_str()); 270*7a0c41d5SAlan Somers } 271*7a0c41d5SAlan Somers strptime(Value(string("timestamp")).c_str(), "%s", &tm_timestamp); 272*7a0c41d5SAlan Somers tv_timestamp.tv_sec = mktime(&tm_timestamp); 273*7a0c41d5SAlan Somers tv_timestamp.tv_usec = 0; 274*7a0c41d5SAlan Somers return (tv_timestamp); 275*7a0c41d5SAlan Somers } 276*7a0c41d5SAlan Somers 277*7a0c41d5SAlan Somers bool 278*7a0c41d5SAlan Somers Event::DevPath(std::string &path) const 279*7a0c41d5SAlan Somers { 280*7a0c41d5SAlan Somers string devName; 281*7a0c41d5SAlan Somers 282*7a0c41d5SAlan Somers if (!DevName(devName)) 283*7a0c41d5SAlan Somers return (false); 284*7a0c41d5SAlan Somers 285*7a0c41d5SAlan Somers string devPath(_PATH_DEV + devName); 286*7a0c41d5SAlan Somers int devFd(open(devPath.c_str(), O_RDONLY)); 287*7a0c41d5SAlan Somers if (devFd == -1) 288*7a0c41d5SAlan Somers return (false); 289*7a0c41d5SAlan Somers 290*7a0c41d5SAlan Somers /* Normalize the device name in case the DEVFS event is for a link. */ 291*7a0c41d5SAlan Somers devName = fdevname(devFd); 292*7a0c41d5SAlan Somers path = _PATH_DEV + devName; 293*7a0c41d5SAlan Somers 294*7a0c41d5SAlan Somers close(devFd); 295*7a0c41d5SAlan Somers 296*7a0c41d5SAlan Somers return (true); 297*7a0c41d5SAlan Somers } 298*7a0c41d5SAlan Somers 299*7a0c41d5SAlan Somers bool 300*7a0c41d5SAlan Somers Event::PhysicalPath(std::string &path) const 301*7a0c41d5SAlan Somers { 302*7a0c41d5SAlan Somers string devPath; 303*7a0c41d5SAlan Somers 304*7a0c41d5SAlan Somers if (!DevPath(devPath)) 305*7a0c41d5SAlan Somers return (false); 306*7a0c41d5SAlan Somers 307*7a0c41d5SAlan Somers int devFd(open(devPath.c_str(), O_RDONLY)); 308*7a0c41d5SAlan Somers if (devFd == -1) 309*7a0c41d5SAlan Somers return (false); 310*7a0c41d5SAlan Somers 311*7a0c41d5SAlan Somers char physPath[MAXPATHLEN]; 312*7a0c41d5SAlan Somers physPath[0] = '\0'; 313*7a0c41d5SAlan Somers bool result(ioctl(devFd, DIOCGPHYSPATH, physPath) == 0); 314*7a0c41d5SAlan Somers close(devFd); 315*7a0c41d5SAlan Somers if (result) 316*7a0c41d5SAlan Somers path = physPath; 317*7a0c41d5SAlan Somers return (result); 318*7a0c41d5SAlan Somers } 319*7a0c41d5SAlan Somers 320*7a0c41d5SAlan Somers //- Event Protected Methods ---------------------------------------------------- 321*7a0c41d5SAlan Somers Event::Event(Type type, NVPairMap &map, const string &eventString) 322*7a0c41d5SAlan Somers : m_type(type), 323*7a0c41d5SAlan Somers m_nvPairs(map), 324*7a0c41d5SAlan Somers m_eventString(eventString) 325*7a0c41d5SAlan Somers { 326*7a0c41d5SAlan Somers } 327*7a0c41d5SAlan Somers 328*7a0c41d5SAlan Somers Event::Event(const Event &src) 329*7a0c41d5SAlan Somers : m_type(src.m_type), 330*7a0c41d5SAlan Somers m_nvPairs(*new NVPairMap(src.m_nvPairs)), 331*7a0c41d5SAlan Somers m_eventString(src.m_eventString) 332*7a0c41d5SAlan Somers { 333*7a0c41d5SAlan Somers } 334*7a0c41d5SAlan Somers 335*7a0c41d5SAlan Somers void 336*7a0c41d5SAlan Somers Event::ParseEventString(Event::Type type, 337*7a0c41d5SAlan Somers const string &eventString, 338*7a0c41d5SAlan Somers NVPairMap& nvpairs) 339*7a0c41d5SAlan Somers { 340*7a0c41d5SAlan Somers size_t start; 341*7a0c41d5SAlan Somers size_t end; 342*7a0c41d5SAlan Somers 343*7a0c41d5SAlan Somers switch (type) { 344*7a0c41d5SAlan Somers case ATTACH: 345*7a0c41d5SAlan Somers case DETACH: 346*7a0c41d5SAlan Somers 347*7a0c41d5SAlan Somers /* 348*7a0c41d5SAlan Somers * <type><device-name><unit> <pnpvars> \ 349*7a0c41d5SAlan Somers * at <location vars> <pnpvars> \ 350*7a0c41d5SAlan Somers * on <parent> 351*7a0c41d5SAlan Somers * 352*7a0c41d5SAlan Somers * Handle all data that doesn't conform to the 353*7a0c41d5SAlan Somers * "name=value" format, and let the generic parser 354*7a0c41d5SAlan Somers * below handle the rest. 355*7a0c41d5SAlan Somers * 356*7a0c41d5SAlan Somers * Type is a single char. Skip it. 357*7a0c41d5SAlan Somers */ 358*7a0c41d5SAlan Somers start = 1; 359*7a0c41d5SAlan Somers end = eventString.find_first_of(" \t\n", start); 360*7a0c41d5SAlan Somers if (end == string::npos) 361*7a0c41d5SAlan Somers throw ParseException(ParseException::INVALID_FORMAT, 362*7a0c41d5SAlan Somers eventString, start); 363*7a0c41d5SAlan Somers 364*7a0c41d5SAlan Somers nvpairs["device-name"] = eventString.substr(start, end - start); 365*7a0c41d5SAlan Somers 366*7a0c41d5SAlan Somers start = eventString.find(" on ", end); 367*7a0c41d5SAlan Somers if (end == string::npos) 368*7a0c41d5SAlan Somers throw ParseException(ParseException::INVALID_FORMAT, 369*7a0c41d5SAlan Somers eventString, start); 370*7a0c41d5SAlan Somers start += 4; 371*7a0c41d5SAlan Somers end = eventString.find_first_of(" \t\n", start); 372*7a0c41d5SAlan Somers nvpairs["parent"] = eventString.substr(start, end); 373*7a0c41d5SAlan Somers break; 374*7a0c41d5SAlan Somers case NOTIFY: 375*7a0c41d5SAlan Somers break; 376*7a0c41d5SAlan Somers case NOMATCH: 377*7a0c41d5SAlan Somers throw ParseException(ParseException::DISCARDED_EVENT_TYPE, 378*7a0c41d5SAlan Somers eventString); 379*7a0c41d5SAlan Somers default: 380*7a0c41d5SAlan Somers throw ParseException(ParseException::UNKNOWN_EVENT_TYPE, 381*7a0c41d5SAlan Somers eventString); 382*7a0c41d5SAlan Somers } 383*7a0c41d5SAlan Somers 384*7a0c41d5SAlan Somers /* Process common "key=value" format. */ 385*7a0c41d5SAlan Somers for (start = 1; start < eventString.length(); start = end + 1) { 386*7a0c41d5SAlan Somers 387*7a0c41d5SAlan Somers /* Find the '=' in the middle of the key/value pair. */ 388*7a0c41d5SAlan Somers end = eventString.find('=', start); 389*7a0c41d5SAlan Somers if (end == string::npos) 390*7a0c41d5SAlan Somers break; 391*7a0c41d5SAlan Somers 392*7a0c41d5SAlan Somers /* 393*7a0c41d5SAlan Somers * Find the start of the key by backing up until 394*7a0c41d5SAlan Somers * we hit whitespace or '!' (event type "notice"). 395*7a0c41d5SAlan Somers * Due to the devdctl format, all key/value pair must 396*7a0c41d5SAlan Somers * start with one of these two characters. 397*7a0c41d5SAlan Somers */ 398*7a0c41d5SAlan Somers start = eventString.find_last_of("! \t\n", end); 399*7a0c41d5SAlan Somers if (start == string::npos) 400*7a0c41d5SAlan Somers throw ParseException(ParseException::INVALID_FORMAT, 401*7a0c41d5SAlan Somers eventString, end); 402*7a0c41d5SAlan Somers start++; 403*7a0c41d5SAlan Somers string key(eventString.substr(start, end - start)); 404*7a0c41d5SAlan Somers 405*7a0c41d5SAlan Somers /* 406*7a0c41d5SAlan Somers * Walk forward from the '=' until either we exhaust 407*7a0c41d5SAlan Somers * the buffer or we hit whitespace. 408*7a0c41d5SAlan Somers */ 409*7a0c41d5SAlan Somers start = end + 1; 410*7a0c41d5SAlan Somers if (start >= eventString.length()) 411*7a0c41d5SAlan Somers throw ParseException(ParseException::INVALID_FORMAT, 412*7a0c41d5SAlan Somers eventString, end); 413*7a0c41d5SAlan Somers end = eventString.find_first_of(" \t\n", start); 414*7a0c41d5SAlan Somers if (end == string::npos) 415*7a0c41d5SAlan Somers end = eventString.length() - 1; 416*7a0c41d5SAlan Somers string value(eventString.substr(start, end - start)); 417*7a0c41d5SAlan Somers 418*7a0c41d5SAlan Somers nvpairs[key] = value; 419*7a0c41d5SAlan Somers } 420*7a0c41d5SAlan Somers } 421*7a0c41d5SAlan Somers 422*7a0c41d5SAlan Somers void 423*7a0c41d5SAlan Somers Event::TimestampEventString(std::string &eventString) 424*7a0c41d5SAlan Somers { 425*7a0c41d5SAlan Somers if (eventString.size() > 0) { 426*7a0c41d5SAlan Somers /* 427*7a0c41d5SAlan Somers * Add a timestamp as the final field of the event if it is 428*7a0c41d5SAlan Somers * not already present. 429*7a0c41d5SAlan Somers */ 430*7a0c41d5SAlan Somers if (eventString.find("timestamp=") == string::npos) { 431*7a0c41d5SAlan Somers const size_t bufsize = 32; // Long enough for a 64-bit int 432*7a0c41d5SAlan Somers timeval now; 433*7a0c41d5SAlan Somers char timebuf[bufsize]; 434*7a0c41d5SAlan Somers 435*7a0c41d5SAlan Somers size_t eventEnd(eventString.find_last_not_of('\n') + 1); 436*7a0c41d5SAlan Somers if (gettimeofday(&now, NULL) != 0) 437*7a0c41d5SAlan Somers err(1, "gettimeofday"); 438*7a0c41d5SAlan Somers snprintf(timebuf, bufsize, " timestamp=%"PRId64, 439*7a0c41d5SAlan Somers (int64_t) now.tv_sec); 440*7a0c41d5SAlan Somers eventString.insert(eventEnd, timebuf); 441*7a0c41d5SAlan Somers } 442*7a0c41d5SAlan Somers } 443*7a0c41d5SAlan Somers } 444*7a0c41d5SAlan Somers 445*7a0c41d5SAlan Somers /*-------------------------------- DevfsEvent --------------------------------*/ 446*7a0c41d5SAlan Somers //- DevfsEvent Static Public Methods ------------------------------------------- 447*7a0c41d5SAlan Somers Event * 448*7a0c41d5SAlan Somers DevfsEvent::Builder(Event::Type type, NVPairMap &nvPairs, 449*7a0c41d5SAlan Somers const string &eventString) 450*7a0c41d5SAlan Somers { 451*7a0c41d5SAlan Somers return (new DevfsEvent(type, nvPairs, eventString)); 452*7a0c41d5SAlan Somers } 453*7a0c41d5SAlan Somers 454*7a0c41d5SAlan Somers //- DevfsEvent Static Protected Methods ---------------------------------------- 455*7a0c41d5SAlan Somers bool 456*7a0c41d5SAlan Somers DevfsEvent::IsWholeDev(const string &devName) 457*7a0c41d5SAlan Somers { 458*7a0c41d5SAlan Somers string::const_iterator i(devName.begin()); 459*7a0c41d5SAlan Somers 460*7a0c41d5SAlan Somers size_t start = devName.rfind('/'); 461*7a0c41d5SAlan Somers if (start == string::npos) { 462*7a0c41d5SAlan Somers start = 0; 463*7a0c41d5SAlan Somers } else { 464*7a0c41d5SAlan Somers /* Just after the last '/'. */ 465*7a0c41d5SAlan Somers start++; 466*7a0c41d5SAlan Somers } 467*7a0c41d5SAlan Somers i += start; 468*7a0c41d5SAlan Somers 469*7a0c41d5SAlan Somers /* alpha prefix followed only by digits. */ 470*7a0c41d5SAlan Somers for (; i < devName.end() && !isdigit(*i); i++) 471*7a0c41d5SAlan Somers ; 472*7a0c41d5SAlan Somers 473*7a0c41d5SAlan Somers if (i == devName.end()) 474*7a0c41d5SAlan Somers return (false); 475*7a0c41d5SAlan Somers 476*7a0c41d5SAlan Somers for (; i < devName.end() && isdigit(*i); i++) 477*7a0c41d5SAlan Somers ; 478*7a0c41d5SAlan Somers 479*7a0c41d5SAlan Somers return (i == devName.end()); 480*7a0c41d5SAlan Somers } 481*7a0c41d5SAlan Somers 482*7a0c41d5SAlan Somers //- DevfsEvent Virtual Public Methods ------------------------------------------ 483*7a0c41d5SAlan Somers Event * 484*7a0c41d5SAlan Somers DevfsEvent::DeepCopy() const 485*7a0c41d5SAlan Somers { 486*7a0c41d5SAlan Somers return (new DevfsEvent(*this)); 487*7a0c41d5SAlan Somers } 488*7a0c41d5SAlan Somers 489*7a0c41d5SAlan Somers bool 490*7a0c41d5SAlan Somers DevfsEvent::Process() const 491*7a0c41d5SAlan Somers { 492*7a0c41d5SAlan Somers return (true); 493*7a0c41d5SAlan Somers } 494*7a0c41d5SAlan Somers 495*7a0c41d5SAlan Somers //- DevfsEvent Public Methods -------------------------------------------------- 496*7a0c41d5SAlan Somers bool 497*7a0c41d5SAlan Somers DevfsEvent::IsWholeDev() const 498*7a0c41d5SAlan Somers { 499*7a0c41d5SAlan Somers string devName; 500*7a0c41d5SAlan Somers 501*7a0c41d5SAlan Somers return (DevName(devName) && IsDiskDev() && IsWholeDev(devName)); 502*7a0c41d5SAlan Somers } 503*7a0c41d5SAlan Somers 504*7a0c41d5SAlan Somers bool 505*7a0c41d5SAlan Somers DevfsEvent::DevName(std::string &name) const 506*7a0c41d5SAlan Somers { 507*7a0c41d5SAlan Somers if (Value("subsystem") != "CDEV") 508*7a0c41d5SAlan Somers return (false); 509*7a0c41d5SAlan Somers 510*7a0c41d5SAlan Somers name = Value("cdev"); 511*7a0c41d5SAlan Somers return (!name.empty()); 512*7a0c41d5SAlan Somers } 513*7a0c41d5SAlan Somers 514*7a0c41d5SAlan Somers //- DevfsEvent Protected Methods ----------------------------------------------- 515*7a0c41d5SAlan Somers DevfsEvent::DevfsEvent(Event::Type type, NVPairMap &nvpairs, 516*7a0c41d5SAlan Somers const string &eventString) 517*7a0c41d5SAlan Somers : Event(type, nvpairs, eventString) 518*7a0c41d5SAlan Somers { 519*7a0c41d5SAlan Somers } 520*7a0c41d5SAlan Somers 521*7a0c41d5SAlan Somers DevfsEvent::DevfsEvent(const DevfsEvent &src) 522*7a0c41d5SAlan Somers : Event(src) 523*7a0c41d5SAlan Somers { 524*7a0c41d5SAlan Somers } 525*7a0c41d5SAlan Somers 526*7a0c41d5SAlan Somers /*--------------------------------- GeomEvent --------------------------------*/ 527*7a0c41d5SAlan Somers //- GeomEvent Static Public Methods -------------------------------------------- 528*7a0c41d5SAlan Somers Event * 529*7a0c41d5SAlan Somers GeomEvent::Builder(Event::Type type, NVPairMap &nvpairs, 530*7a0c41d5SAlan Somers const string &eventString) 531*7a0c41d5SAlan Somers { 532*7a0c41d5SAlan Somers return (new GeomEvent(type, nvpairs, eventString)); 533*7a0c41d5SAlan Somers } 534*7a0c41d5SAlan Somers 535*7a0c41d5SAlan Somers //- GeomEvent Virtual Public Methods ------------------------------------------- 536*7a0c41d5SAlan Somers Event * 537*7a0c41d5SAlan Somers GeomEvent::DeepCopy() const 538*7a0c41d5SAlan Somers { 539*7a0c41d5SAlan Somers return (new GeomEvent(*this)); 540*7a0c41d5SAlan Somers } 541*7a0c41d5SAlan Somers 542*7a0c41d5SAlan Somers bool 543*7a0c41d5SAlan Somers GeomEvent::DevName(std::string &name) const 544*7a0c41d5SAlan Somers { 545*7a0c41d5SAlan Somers name = Value("devname"); 546*7a0c41d5SAlan Somers return (!name.empty()); 547*7a0c41d5SAlan Somers } 548*7a0c41d5SAlan Somers 549*7a0c41d5SAlan Somers 550*7a0c41d5SAlan Somers //- GeomEvent Protected Methods ------------------------------------------------ 551*7a0c41d5SAlan Somers GeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs, 552*7a0c41d5SAlan Somers const string &eventString) 553*7a0c41d5SAlan Somers : Event(type, nvpairs, eventString), 554*7a0c41d5SAlan Somers m_devname(Value("devname")) 555*7a0c41d5SAlan Somers { 556*7a0c41d5SAlan Somers } 557*7a0c41d5SAlan Somers 558*7a0c41d5SAlan Somers GeomEvent::GeomEvent(const GeomEvent &src) 559*7a0c41d5SAlan Somers : Event(src), 560*7a0c41d5SAlan Somers m_devname(src.m_devname) 561*7a0c41d5SAlan Somers { 562*7a0c41d5SAlan Somers } 563*7a0c41d5SAlan Somers 564*7a0c41d5SAlan Somers /*--------------------------------- ZfsEvent ---------------------------------*/ 565*7a0c41d5SAlan Somers //- ZfsEvent Static Public Methods --------------------------------------------- 566*7a0c41d5SAlan Somers Event * 567*7a0c41d5SAlan Somers ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs, 568*7a0c41d5SAlan Somers const string &eventString) 569*7a0c41d5SAlan Somers { 570*7a0c41d5SAlan Somers return (new ZfsEvent(type, nvpairs, eventString)); 571*7a0c41d5SAlan Somers } 572*7a0c41d5SAlan Somers 573*7a0c41d5SAlan Somers //- ZfsEvent Virtual Public Methods -------------------------------------------- 574*7a0c41d5SAlan Somers Event * 575*7a0c41d5SAlan Somers ZfsEvent::DeepCopy() const 576*7a0c41d5SAlan Somers { 577*7a0c41d5SAlan Somers return (new ZfsEvent(*this)); 578*7a0c41d5SAlan Somers } 579*7a0c41d5SAlan Somers 580*7a0c41d5SAlan Somers bool 581*7a0c41d5SAlan Somers ZfsEvent::DevName(std::string &name) const 582*7a0c41d5SAlan Somers { 583*7a0c41d5SAlan Somers return (false); 584*7a0c41d5SAlan Somers } 585*7a0c41d5SAlan Somers 586*7a0c41d5SAlan Somers //- ZfsEvent Protected Methods ------------------------------------------------- 587*7a0c41d5SAlan Somers ZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs, 588*7a0c41d5SAlan Somers const string &eventString) 589*7a0c41d5SAlan Somers : Event(type, nvpairs, eventString), 590*7a0c41d5SAlan Somers m_poolGUID(Guid(Value("pool_guid"))), 591*7a0c41d5SAlan Somers m_vdevGUID(Guid(Value("vdev_guid"))) 592*7a0c41d5SAlan Somers { 593*7a0c41d5SAlan Somers } 594*7a0c41d5SAlan Somers 595*7a0c41d5SAlan Somers ZfsEvent::ZfsEvent(const ZfsEvent &src) 596*7a0c41d5SAlan Somers : Event(src), 597*7a0c41d5SAlan Somers m_poolGUID(src.m_poolGUID), 598*7a0c41d5SAlan Somers m_vdevGUID(src.m_vdevGUID) 599*7a0c41d5SAlan Somers { 600*7a0c41d5SAlan Somers } 601*7a0c41d5SAlan Somers 602*7a0c41d5SAlan Somers } // namespace DevdCtl 603