static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make) { insp::flat_set<std::string> configlines; ConfigTagList tags = conf->ConfTags(tag); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* ctag = i->second; std::string mask; if (!ctag->readString(key, mask)) throw CoreException("<"+tag+":"+key+"> missing at " + ctag->getTagLocation()); std::string reason = ctag->getString("reason", "<Config>"); XLine* xl = make->Generate(ServerInstance->Time(), 0, "<Config>", reason, mask); xl->from_config = true; configlines.insert(xl->Displayable()); if (!ServerInstance->XLines->AddLine(xl, NULL)) delete xl; } ServerInstance->XLines->ExpireRemovedConfigLines(make->GetType(), configlines); }
bool WriteDatabase() { /* * We need to perform an atomic write so as not to f**k things up. * So, let's write to a temporary file, flush it, then rename the file.. * Technically, that means that this can block, but I have *never* seen that. * -- w00t */ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opening temporary database"); std::string xlinenewdbpath = xlinedbpath + ".new"; std::ofstream stream(xlinenewdbpath.c_str()); if (!stream.is_open()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot create database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno); return false; } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Opened. Writing.."); /* * Now, much as I hate writing semi-unportable formats, additional * xline types may not have a conf tag, so let's just write them. * In addition, let's use a file version, so we can maintain some * semblance of backwards compatibility for reading on startup.. * -- w00t */ stream << "VERSION 1" << std::endl; // Now, let's write. std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it) { XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); if (!lookup) continue; // Not possible as we just obtained the list from XLineManager for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) { XLine* line = i->second; stream << "LINE " << line->type << " " << line->Displayable() << " " << ServerInstance->Config->ServerName << " " << line->set_time << " " << line->duration << " " << line->reason << std::endl; } } ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Finished writing XLines. Checking for error.."); if (stream.fail()) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot write to new database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno); return false; } stream.close(); #ifdef _WIN32 if (remove(xlinedbpath.c_str())) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot remove old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno); return false; } #endif // Use rename to move temporary to new db - this is guarenteed not to f**k up, even in case of a crash. if (rename(xlinenewdbpath.c_str(), xlinedbpath.c_str()) < 0) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cannot move new to old database! %s (%d)", strerror(errno), errno); ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno); return false; } return true; }