2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com>
5 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
6 * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
8 * This file is part of InspIRCd. InspIRCd is free software: you can
9 * redistribute it and/or modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation, version 2.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "modules/reload.h"
26 static Events::ModuleEventProvider* reloadevprov;
28 class CommandReloadmodule : public Command
30 Events::ModuleEventProvider evprov;
32 /** Constructor for reloadmodule.
34 CommandReloadmodule(Module* parent)
35 : Command(parent, "RELOADMODULE", 1)
36 , evprov(parent, "event/reloadmodule")
38 reloadevprov = &evprov;
40 syntax = "<modulename>";
44 * @param parameters The parameters to the command
45 * @param user The user issuing the command
46 * @return A value from CmdResult to indicate command success or failure.
48 CmdResult Handle(const std::vector<std::string>& parameters, User *user);
51 namespace ReloadModule
56 /** Data we save for each mode and extension provided by the module
64 ExtensionItem* extitem;
67 ProviderInfo(ModeHandler* mode)
68 : itemname(mode->name)
73 ProviderInfo(ExtensionItem* ei)
82 /** Position of the ModeHandler or ExtensionItem that the serialized data belongs to
88 std::string serialized;
90 InstanceData(size_t Index, const std::string& Serialized)
92 , serialized(Serialized)
99 /** Mode data for the object, one entry per mode set by the module being reloaded
101 std::vector<InstanceData> modelist;
103 /** Extensions for the object, one entry per extension set by the module being reloaded
105 std::vector<InstanceData> extlist;
107 bool empty() const { return ((modelist.empty()) && (extlist.empty())); }
109 void swap(ModesExts& other)
111 modelist.swap(other.modelist);
112 extlist.swap(other.extlist);
116 struct OwnedModesExts : public ModesExts
118 /** User uuid or channel name
122 OwnedModesExts(const std::string& Owner)
128 // Data saved for each channel
129 struct ChanData : public OwnedModesExts
131 /** Type of data stored for each member who has any affected modes or extensions set
133 typedef OwnedModesExts MemberData;
135 /** List of data (modes and extensions) about each member
137 std::vector<MemberData> memberdatalist;
139 ChanData(Channel* chan)
140 : OwnedModesExts(chan->name)
145 // Data saved for each user
146 typedef OwnedModesExts UserData;
148 /** Module being reloaded
152 /** Stores all user and channel modes provided by the module
154 std::vector<ProviderInfo> handledmodes[2];
156 /** Stores all extensions provided by the module
158 std::vector<ProviderInfo> handledexts;
160 /** Stores all of the module data related to users
162 std::vector<UserData> userdatalist;
164 /** Stores all of the module data related to channels and memberships
166 std::vector<ChanData> chandatalist;
168 /** Data attached by modules
170 ReloadModule::CustomData moddata;
172 void SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdatalist);
173 void SaveMemberData(Channel* chan, std::vector<ChanData::MemberData>& memberdatalist);
174 static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata);
176 void CreateModeList(ModeType modetype);
180 /** Link previously saved extension names to currently available ExtensionItems
182 void LinkExtensions();
184 /** Link previously saved mode names to currently available ModeHandlers
185 * @param modetype Type of the modes to look for
187 void LinkModes(ModeType modetype);
189 void DoRestoreUsers();
190 void DoRestoreChans();
191 void DoRestoreModules();
193 /** Restore previously saved modes and extensions on an Extensible.
194 * The extensions are set directly on the extensible, the modes are added into the provided mode change list.
195 * @param data Data to unserialize from
196 * @param extensible Object to restore
197 * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
198 * (for Channels and Memberships).
199 * @param modechange Mode change to populate with the modes
201 void RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange);
203 /** Restore all previously saved extensions on an Extensible
204 * @param list List of extensions and their serialized data to restore
205 * @param extensible Target Extensible
207 void RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible);
209 /** Restore all previously saved modes on a User, Channel or Membership
210 * @param list List of modes to restore
211 * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
212 * @param modechange Mode change to populate with the modes
214 void RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange);
216 /** Restore all modes and extensions of all members on a channel
217 * @param chan Channel whose members are being restored
218 * @param memberdata Data to restore
219 * @param modechange Mode change to populate with prefix modes
221 void RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange);
223 /** Verify that a service which had its data saved is available and owned by the module that owned it previously
224 * @param service Service descriptor
225 * @param type Human-readable type of the service for log messages
227 void VerifyServiceProvider(const ProviderInfo& service, const char* type);
230 /** Save module state
231 * @param currmod Module whose data to save
233 void Save(Module* currmod);
235 /** Restore module state
236 * @param newmod Newly loaded instance of the module which had its data saved
238 void Restore(Module* newmod);
240 /** Handle reload failure
245 void DataKeeper::DoSaveUsers()
249 const user_hash& users = ServerInstance->Users->GetUsers();
250 for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
252 User* const user = i->second;
254 // Serialize user modes
255 for (size_t j = 0; j < handledmodes[MODETYPE_USER].size(); j++)
257 ModeHandler* mh = handledmodes[MODETYPE_USER][j].mh;
258 if (user->IsModeSet(mh))
259 currdata.modelist.push_back(InstanceData(j, mh->GetUserParameter(user)));
262 // Serialize all extensions attached to the User
263 SaveExtensions(user, currdata.extlist);
265 // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't
266 // have to do anything with this user when restoring
267 if (!currdata.empty())
269 userdatalist.push_back(UserData(user->uuid));
270 userdatalist.back().swap(currdata);
275 void DataKeeper::SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdata)
277 const Extensible::ExtensibleStore& setexts = extensible->GetExtList();
279 // Position of the extension saved in the handledexts list
281 for (std::vector<ProviderInfo>::const_iterator i = handledexts.begin(); i != handledexts.end(); ++i, index++)
283 ExtensionItem* const item = i->extitem;
284 Extensible::ExtensibleStore::const_iterator it = setexts.find(item);
285 if (it == setexts.end())
288 std::string value = item->serialize(FORMAT_INTERNAL, extensible, it->second);
289 // If the serialized value is empty the extension won't be saved and restored
291 extdata.push_back(InstanceData(index, value));
295 void DataKeeper::SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata)
297 const ListModeBase::ModeList* list = lm->GetList(chan);
301 for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
303 const ListModeBase::ListItem& listitem = *i;
304 currdata.modelist.push_back(InstanceData(index, listitem.mask));
308 void DataKeeper::DoSaveChans()
311 std::vector<OwnedModesExts> currmemberdata;
313 const chan_hash& chans = ServerInstance->GetChans();
314 for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
316 Channel* const chan = i->second;
318 // Serialize channel modes
319 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
321 ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
322 ListModeBase* lm = mh->IsListModeBase();
324 SaveListModes(chan, lm, j, currdata);
325 else if (chan->IsModeSet(mh))
326 currdata.modelist.push_back(InstanceData(j, chan->GetModeParameter(mh)));
329 // Serialize all extensions attached to the Channel
330 SaveExtensions(chan, currdata.extlist);
332 // Serialize all extensions attached to and all modes set on all members of the channel
333 SaveMemberData(chan, currmemberdata);
335 // Same logic as in DoSaveUsers() plus we consider the modes and extensions of all members
336 if ((!currdata.empty()) || (!currmemberdata.empty()))
338 chandatalist.push_back(ChanData(chan));
339 chandatalist.back().swap(currdata);
340 chandatalist.back().memberdatalist.swap(currmemberdata);
345 void DataKeeper::SaveMemberData(Channel* chan, std::vector<OwnedModesExts>& memberdatalist)
348 const Channel::MemberMap& users = chan->GetUsers();
349 for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
351 Membership* const memb = i->second;
353 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
355 ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
356 if ((mh->IsPrefixMode()) && (memb->hasMode(mh->GetModeChar())))
357 currdata.modelist.push_back(InstanceData(j, memb->user->uuid)); // Need to pass the user's uuid to the mode parser to set the mode later
360 SaveExtensions(memb, currdata.extlist);
362 // Same logic as in DoSaveUsers()
363 if (!currdata.empty())
365 memberdatalist.push_back(OwnedModesExts(memb->user->uuid));
366 memberdatalist.back().swap(currdata);
371 void DataKeeper::RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange)
373 for (std::vector<ChanData::MemberData>::const_iterator i = memberdatalist.begin(); i != memberdatalist.end(); ++i)
375 const ChanData::MemberData& md = *i;
376 User* const user = ServerInstance->FindUUID(md.owner);
379 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone (while processing %s)", md.owner.c_str(), chan->name.c_str());
383 Membership* const memb = chan->GetUser(user);
386 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Member %s is no longer on channel %s", md.owner.c_str(), chan->name.c_str());
390 RestoreObj(md, memb, MODETYPE_CHANNEL, modechange);
394 void DataKeeper::CreateModeList(ModeType modetype)
396 const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes->GetModes(modetype);
397 for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ++i)
399 ModeHandler* mh = i->second;
400 if (mh->creator == mod)
401 handledmodes[modetype].push_back(ProviderInfo(mh));
405 void DataKeeper::Save(Module* currmod)
409 const ExtensionManager::ExtMap& allexts = ServerInstance->Extensions.GetExts();
410 for (ExtensionManager::ExtMap::const_iterator i = allexts.begin(); i != allexts.end(); ++i)
412 ExtensionItem* ext = i->second;
413 if (ext->creator == mod)
414 handledexts.push_back(ProviderInfo(ext));
417 CreateModeList(MODETYPE_USER);
420 CreateModeList(MODETYPE_CHANNEL);
423 FOREACH_MOD_CUSTOM(*reloadevprov, ReloadModule::EventListener, OnReloadModuleSave, (mod, this->moddata));
425 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Saved data about %lu users %lu chans %lu modules", (unsigned long)userdatalist.size(), (unsigned long)chandatalist.size(), (unsigned long)moddata.list.size());
428 void DataKeeper::VerifyServiceProvider(const ProviderInfo& service, const char* type)
430 const ServiceProvider* sp = service.extitem;
432 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is no longer available", type, service.itemname.c_str());
433 else if (sp->creator != mod)
434 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is now handled by %s", type, service.itemname.c_str(), (sp->creator ? sp->creator->ModuleSourceFile.c_str() : "<core>"));
437 void DataKeeper::LinkModes(ModeType modetype)
439 std::vector<ProviderInfo>& list = handledmodes[modetype];
440 for (std::vector<ProviderInfo>::iterator i = list.begin(); i != list.end(); ++i)
442 ProviderInfo& item = *i;
443 item.mh = ServerInstance->Modes->FindMode(item.itemname, modetype);
444 VerifyServiceProvider(item, (modetype == MODETYPE_USER ? "User mode" : "Channel mode"));
448 void DataKeeper::LinkExtensions()
450 for (std::vector<ProviderInfo>::iterator i = handledexts.begin(); i != handledexts.end(); ++i)
452 ProviderInfo& item = *i;
453 item.extitem = ServerInstance->Extensions.GetItem(item.itemname);
454 VerifyServiceProvider(item.extitem, "Extension");
458 void DataKeeper::Restore(Module* newmod)
462 // Find the new extension items
464 LinkModes(MODETYPE_USER);
465 LinkModes(MODETYPE_CHANNEL);
472 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore finished");
475 void DataKeeper::Fail()
479 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore failed, notifying modules");
483 void DataKeeper::RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange)
485 RestoreExtensions(data.extlist, extensible);
486 RestoreModes(data.modelist, modetype, modechange);
489 void DataKeeper::RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible)
491 for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
493 const InstanceData& id = *i;
494 handledexts[id.index].extitem->unserialize(FORMAT_INTERNAL, extensible, id.serialized);
498 void DataKeeper::RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange)
500 for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
502 const InstanceData& id = *i;
503 modechange.push_add(handledmodes[modetype][id.index].mh, id.serialized);
507 void DataKeeper::DoRestoreUsers()
509 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data");
510 Modes::ChangeList modechange;
512 for (std::vector<UserData>::const_iterator i = userdatalist.begin(); i != userdatalist.end(); ++i)
514 const UserData& userdata = *i;
515 User* const user = ServerInstance->FindUUID(userdata.owner);
518 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone", userdata.owner.c_str());
522 RestoreObj(userdata, user, MODETYPE_USER, modechange);
523 ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY);
528 void DataKeeper::DoRestoreChans()
530 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring channel data");
531 Modes::ChangeList modechange;
533 for (std::vector<ChanData>::const_iterator i = chandatalist.begin(); i != chandatalist.end(); ++i)
535 const ChanData& chandata = *i;
536 Channel* const chan = ServerInstance->FindChan(chandata.owner);
539 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel %s not found", chandata.owner.c_str());
543 RestoreObj(chandata, chan, MODETYPE_CHANNEL, modechange);
544 // Process the mode change before applying any prefix modes
545 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
548 // Restore all member data
549 RestoreMemberData(chan, chandata.memberdatalist, modechange);
550 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
555 void DataKeeper::DoRestoreModules()
557 for (ReloadModule::CustomData::List::iterator i = moddata.list.begin(); i != moddata.list.end(); ++i)
559 ReloadModule::CustomData::Data& data = *i;
560 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Calling module data handler %p", (void*)data.handler);
561 data.handler->OnReloadModuleRestore(mod, data.data);
565 } // namespace ReloadModule
567 class ReloadAction : public HandlerBase0<void>
570 const std::string uuid;
571 const std::string passedname;
574 ReloadAction(Module* m, const std::string& uid, const std::string& passedmodname)
577 , passedname(passedmodname)
583 ReloadModule::DataKeeper datakeeper;
584 datakeeper.Save(mod);
586 DLLManager* dll = mod->ModuleDLLManager;
587 std::string name = mod->ModuleSourceFile;
588 ServerInstance->Modules->DoSafeUnload(mod);
589 ServerInstance->GlobalCulls.Apply();
591 bool result = ServerInstance->Modules->Load(name);
595 Module* newmod = ServerInstance->Modules->Find(name);
596 datakeeper.Restore(newmod);
601 ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded", passedname.c_str(), result ? "" : "un");
602 User* user = ServerInstance->FindUUID(uuid);
604 user->WriteNumeric(RPL_LOADEDMODULE, "%s :Module %ssuccessfully reloaded.", passedname.c_str(), result ? "" : "un");
606 ServerInstance->GlobalCulls.AddItem(this);
610 CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameters, User *user)
612 Module* m = ServerInstance->Modules->Find(parameters[0]);
615 user->WriteNumeric(RPL_LOADEDMODULE, "%s :You cannot reload core_reloadmodule.so (unload and load it)",
616 parameters[0].c_str());
623 if ((m) && (ServerInstance->Modules.CanUnload(m)))
625 ServerInstance->AtomicActions.AddAction(new ReloadAction(m, user->uuid, parameters[0]));
630 user->WriteNumeric(RPL_LOADEDMODULE, "%s :Could not find module by that name", parameters[0].c_str());
635 COMMAND_INIT(CommandReloadmodule)