1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-25 17:06:38 +02:00
Files
unrealircd/src/api-moddata.c
T
Bram Matthys 9fc1e758ab Mass change of dst = strdup(str) to safe_strdup(dst,str) but with a manual
audit since 'dst' must now be initialized memory.
There's still a raw_strdup() if you insist.

This is step 2 of X of memory allocation changes
2019-09-14 16:58:01 +02:00

392 lines
8.9 KiB
C

/************************************************************************
* IRC - Internet Relay Chat, src/api-moddata.c
* (C) 2003-2019 Bram Matthys (Syzop) and the UnrealIRCd Team
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "unrealircd.h"
MODVAR ModDataInfo *MDInfo = NULL;
MODVAR ModData localvar_moddata[MODDATA_MAX_LOCALVAR];
MODVAR ModData globalvar_moddata[MODDATA_MAX_GLOBALVAR];
ModDataInfo *ModDataAdd(Module *module, ModDataInfo req)
{
int slotav = 0; /* highest available slot */
ModDataInfo *m;
int new_struct = 0;
/* Hunt for highest available slot */
for (m = MDInfo; m ; m = m->next)
if (m->type == req.type)
{
/* Does an entry already exist with this name? */
if (!strcmp(m->name, req.name))
{
/* If old module is unloading (so reloading), then OK to take this slot */
if (m->unloaded)
{
slotav = m->slot;
m->unloaded = 0;
goto moddataadd_isok;
}
/* Otherwise, name collision */
if (module)
module->errorcode = MODERR_EXISTS;
return NULL;
}
/* Update next available slot */
slotav = MAX(slotav, m->slot+1);
}
/* Now check if we are within bounds (if we really have a free slot available) */
if (((req.type == MODDATATYPE_LOCALVAR) && (slotav >= MODDATA_MAX_LOCALVAR)) ||
((req.type == MODDATATYPE_GLOBALVAR) && (slotav >= MODDATA_MAX_GLOBALVAR)) ||
((req.type == MODDATATYPE_CLIENT) && (slotav >= MODDATA_MAX_CLIENT)) ||
((req.type == MODDATATYPE_CHANNEL) && (slotav >= MODDATA_MAX_CHANNEL)) ||
((req.type == MODDATATYPE_MEMBER) && (slotav >= MODDATA_MAX_MEMBER)) ||
((req.type == MODDATATYPE_MEMBERSHIP) && (slotav >= MODDATA_MAX_MEMBERSHIP)))
{
if (module)
module->errorcode = MODERR_NOSPACE;
return NULL;
}
new_struct = 1;
m = safe_alloc(sizeof(ModDataInfo));
safe_strdup(m->name, req.name);
m->slot = slotav;
m->type = req.type;
moddataadd_isok:
m->free = req.free;
m->serialize = req.serialize;
m->unserialize = req.unserialize;
m->sync = req.sync;
m->owner = module;
if (new_struct)
AddListItem(m, MDInfo);
if (module)
{
ModuleObject *mobj = safe_alloc(sizeof(ModuleObject));
mobj->object.moddata = m;
mobj->type = MOBJ_MODDATA;
AddListItem(mobj, module->objects);
module->errorcode = MODERR_NOERROR;
}
return m;
}
void moddata_free_client(Client *acptr)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_CLIENT)
{
if (md->free && moddata_client(acptr, md).ptr)
md->free(&moddata_client(acptr, md));
}
memset(acptr->moddata, 0, sizeof(acptr->moddata));
}
// FIXME: this is never called
void moddata_free_channel(Channel *chptr)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_CHANNEL)
{
if (md->free && moddata_channel(chptr, md).ptr)
md->free(&moddata_channel(chptr, md));
}
memset(chptr->moddata, 0, sizeof(chptr->moddata));
}
void moddata_free_member(Member *m)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_MEMBER)
{
if (md->free && moddata_member(m, md).ptr)
md->free(&moddata_member(m, md));
}
memset(m->moddata, 0, sizeof(m->moddata));
}
void moddata_free_membership(Membership *m)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->type == MODDATATYPE_MEMBERSHIP)
{
if (md->free && moddata_membership(m, md).ptr)
md->free(&moddata_membership(m, md));
}
memset(m->moddata, 0, sizeof(m->moddata));
}
/** Actually free all the ModData from all objects */
void unload_moddata_commit(ModDataInfo *md)
{
switch(md->type)
{
case MODDATATYPE_LOCALVAR:
if (md->free && moddata_localvar(md).ptr)
md->free(&moddata_localvar(md));
memset(&moddata_localvar(md), 0, sizeof(ModData));
break;
case MODDATATYPE_GLOBALVAR:
if (md->free && moddata_globalvar(md).ptr)
md->free(&moddata_globalvar(md));
memset(&moddata_globalvar(md), 0, sizeof(ModData));
break;
case MODDATATYPE_CLIENT:
{
Client *acptr;
list_for_each_entry(acptr, &lclient_list, lclient_node)
{
if (md->free && moddata_client(acptr, md).ptr)
{
md->free(&moddata_client(acptr, md));
}
memset(&moddata_client(acptr, md), 0, sizeof(ModData));
}
break;
}
case MODDATATYPE_CHANNEL:
{
Channel *chptr;
for (chptr = channel; chptr; chptr=chptr->nextch)
{
if (md->free && moddata_channel(chptr, md).ptr)
md->free(&moddata_channel(chptr, md));
memset(&moddata_channel(chptr, md), 0, sizeof(ModData));
}
break;
}
case MODDATATYPE_MEMBER:
{
Channel *chptr;
Member *m;
for (chptr = channel; chptr; chptr=chptr->nextch)
{
for (m = chptr->members; m; m = m->next)
{
if (md->free && moddata_member(m, md).ptr)
md->free(&moddata_member(m, md));
memset(&moddata_member(m, md), 0, sizeof(ModData));
}
}
break;
}
case MODDATATYPE_MEMBERSHIP:
{
Client *acptr;
Membership *m;
list_for_each_entry(acptr, &lclient_list, lclient_node)
{
if (!acptr->user)
continue;
for (m = acptr->user->channel; m; m = m->next)
{
if (md->free && moddata_membership(m, md).ptr)
md->free(&moddata_membership(m, md));
memset(&moddata_membership(m, md), 0, sizeof(ModData));
}
}
break;
}
}
DelListItem(md, MDInfo);
safe_free(md->name);
safe_free(md);
}
void ModDataDel(ModDataInfo *md)
{
/* Delete the reference to us first */
if (md->owner)
{
ModuleObject *mdobj;
for (mdobj = md->owner->objects; mdobj; mdobj = mdobj->next)
{
if ((mdobj->type == MOBJ_MODDATA) && (mdobj->object.moddata == md))
{
DelListItem(mdobj, md->owner->objects);
safe_free(mdobj);
break;
}
}
md->owner = NULL;
}
if (loop.ircd_rehashing)
md->unloaded = 1;
else
unload_moddata_commit(md);
}
void unload_all_unused_moddata(void)
{
ModDataInfo *md, *md_next;
for (md = MDInfo; md; md = md_next)
{
md_next = md->next;
if (md->unloaded)
unload_moddata_commit(md);
}
}
ModDataInfo *findmoddata_byname(char *name, ModDataType type)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if ((md->type == type) && !strcmp(name, md->name))
return md;
return NULL;
}
int module_has_moddata(Module *mod)
{
ModDataInfo *md;
for (md = MDInfo; md; md = md->next)
if (md->owner == mod)
return 1;
return 0;
}
/** Set ModData for client (via variable name, string value) */
int moddata_client_set(Client *acptr, char *varname, char *value)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
if (!md)
return 0;
if (value)
{
/* SET */
md->unserialize(value, &moddata_client(acptr, md));
}
else
{
/* UNSET */
md->free(&moddata_client(acptr, md));
memset(&moddata_client(acptr, md), 0, sizeof(ModData));
}
/* If 'sync' field is set and the client is not in pre-registered
* state then broadcast the new setting.
*/
if (md->sync && (IsUser(acptr) || IsServer(acptr) || IsMe(acptr)))
broadcast_md_client_cmd(NULL, &me, acptr, md->name, value);
return 1;
}
/** Get ModData for client (via variable name) */
char *moddata_client_get(Client *acptr, char *varname)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_CLIENT);
if (!md)
return NULL;
return md->serialize(&moddata_client(acptr, md)); /* can be NULL */
}
/** Set localvar or globalvar moddata (via variable name, string value) */
int moddata_localvar_set(char *varname, char *value)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_LOCALVAR);
if (!md)
return 0;
if (value)
{
/* SET */
md->unserialize(value, &moddata_localvar(md));
}
else
{
/* UNSET */
md->free(&moddata_localvar(md));
memset(&moddata_localvar(md), 0, sizeof(ModData));
}
return 1;
}
/** Set globalvar or globalvar moddata (via variable name, string value) */
int moddata_globalvar_set(char *varname, char *value)
{
ModDataInfo *md;
md = findmoddata_byname(varname, MODDATATYPE_GLOBALVAR);
if (!md)
return 0;
if (value)
{
/* SET */
md->unserialize(value, &moddata_globalvar(md));
}
else
{
/* UNSET */
md->free(&moddata_globalvar(md));
memset(&moddata_globalvar(md), 0, sizeof(ModData));
}
if (md->sync)
broadcast_md_globalvar_cmd(NULL, &me, md->name, value);
return 1;
}
/* The rest of the MD related functions, the send/receive functions,
* are in src/modules/md.c
*/