1
0
mirror of https://github.com/deadw00d/AROS.git synced 2025-12-06 13:11:35 +00:00
Files
AROS-v0/workbench/devs/netinfo/entries.c

462 lines
12 KiB
C

/*
* General DB routines
*
* Author: ppessi <Pekka.Pessi@hut.fi>
*
* Copyright © 1993 AmiTCP/IP Group, <AmiTCP-group@hut.fi>
* Helsinki University of Technology, Finland.
*/
#include <proto/exec.h>
#include <proto/dos.h>
#include "entries.h"
#include <string.h>
#if defined(DEBUG)
#include <assert.h>
#include "assert.h"
#endif
static struct NetInfoPointer *FindPointer(struct List *list, struct Ent*to);
void GetByNameCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
void GetByIDCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
void ResetCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
void ReadCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
void WriteCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
void UpdateCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
void MembersCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
const static DeviceCmd_t map_cmds[NI_END] = {
/* Standard commands */
UnknownCommand, /* CMD_INVALID */
ResetCmd, /* CMD_RESET */
ReadCmd, /* CMD_READ */
WriteCmd, /* CMD_WRITE */
UpdateCmd, /* CMD_UPDATE */
UnknownCommand, /* CMD_CLEAR */
UnknownCommand, /* CMD_STOP */
UnknownCommand, /* CMD_START */
UnknownCommand, /* CMD_FLUSH */
/* NetInfo commands */
GetByIDCmd, /* NI_GETBYID */
GetByNameCmd, /* NI_GETBYNAME */
MembersCmd, /* NI_MEMBERS */
};
static const init_map_func_t initMapFuncs[NETINFO_UNITS] = {
InitPasswdMap,
InitGroupMap,
};
struct NetInfoMap *InitNetInfoMap(struct NetInfoDevice *nid, struct MsgPort * mp, ULONG mapno)
{
struct NetInfoMap *nim;
#if defined(DEBUG)
assert(mapno < 2);
#endif
if (nim = initMapFuncs[mapno](nid)) {
nim->nim_Port = mp;
nim->nim_Commands = map_cmds;
InitSemaphore(nim->nim_ReqLock);
NEWLIST(nim->nim_Rx);
NEWLIST(nim->nim_Wx);
InitSemaphore(nim->nim_EntLock);
NEWLIST(nim->nim_Ent);
InitSemaphore(nim->nim_PointerLock);
NEWLIST(nim->nim_Pointer);
}
return nim;
}
void DeInitNetInfoMap(struct NetInfoDevice *nid, struct NetInfoMap *nim)
{
if (Method(cleanup, nim) != NULL)
Method(cleanup, nim)(nid, nim);
FreeVec(nim);
}
/*
* NI_GETBYNAME, search an entry by name
*/
void GetByNameCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
{
struct Ent *e = InternalSetEnts(nid, nim);
const UBYTE *name = (const UBYTE *)
((struct NetInfoEnt*)req->io_Data)->nie_name;
LONG retval = NIERR_NOTFOUND;
while (e = GetNextEnt(e)) {
if (strcmp(e->e_name, name) == 0) {
if (Method(copy_out, nim)(req, e)) {
retval = 0;
} else {
retval = NIERR_TOOSMALL;
}
break;
}
}
req->io_Error = retval;
InternalEndEnts(nid, nim);
TermIO(req);
}
/*
* NI_GETBYID, Search an entry by ID
*/
void GetByIDCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
{
struct Ent *e = InternalSetEnts(nid, nim);
LONG id = ((struct NetInfoEnt*)req->io_Data)->nie_id;
BYTE retval = NIERR_NOTFOUND;
while (e = GetNextEnt(e)) {
if (e->e_id == id) {
if (Method(copy_out, nim)(req, e)) {
retval = 0;
} else {
retval = NIERR_TOOSMALL;
}
break;
}
}
req->io_Error = retval;
InternalEndEnts(nid, nim);
TermIO(req);
}
/*
* CMD_RESET, start reading the database in sequential order
*/
void ResetCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
{
struct NetInfoPointer *p = (struct NetInfoPointer *)req->io_Unit;
p->nip_Ent = (void *)InternalSetEnts(nid, nim);
InternalEndEnts(nid, nim);
req->io_Error = 0;
TermIO(req);
}
/*
* CMD_READ, get next entry
*/
void ReadCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
{
struct NetInfoPointer *p = (struct NetInfoPointer *)req->io_Unit;
struct Ent *e;
BYTE retval;
InternalSetEnts(nid, nim);
e = p->nip_Ent;
if (p->nip_Ent && (p->nip_Ent = GetNextEnt(e))) {
if (Method(copy_out, nim)(req, p->nip_Ent)) {
retval = 0;
} else {
retval = NIERR_TOOSMALL;
}
} else {
retval = NIERR_NOTFOUND;
}
InternalEndEnts(nid, nim);
req->io_Error = retval;
TermIO(req);
}
/*
* CMD_WRITE
*/
void WriteCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
{
struct Ent *e, *new_e;
const UBYTE *name = ((struct NetInfoPasswd *)req->io_Data)->pw_name;
if (new_e = Method(copy_in, nim)(nid, req)) {
/* Exclusive lock for writing */
DbMapLock(nim);
e = InternalSetEnts(nid, nim);
while (e = GetNextEnt(e)) {
if (strcmp(e->e_name, name) == 0) {
/* A match was found - add new */
Insert(nim->nim_Ent, (struct Node *)new_e, (struct Node *)e);
/* Remove old */
Remove((struct Node *)e);
/* Update pointers */
ObtainSemaphore(nim->nim_PointerLock);
{
struct NetInfoPointer *nip;
if (nip = FindPointer(nim->nim_Pointer, e)) {
nip->nip_Ent = (void *)new_e;
}
}
ReleaseSemaphore(nim->nim_PointerLock);
/* Free old */
FreeVec(e);
new_e = NULL;
break;
}
}
/*
* A new entry?
*/
if (new_e != NULL) {
AddTail(nim->nim_Ent, (struct Node *)new_e);
}
req->io_Error = 0;
InternalEndEnts(nid, nim);
nim->nim_Flags |= NIMF_CHANGED;
DbMapUnlock(nim);
} else {
/* copy_in method will set the io_Error */
}
TermIO(req);
}
/*
* CMD_UPDATE
*/
void UpdateCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
{
BYTE retval = 0;
if ((nim->nim_Flags & NIMF_CHANGED) != 0) {
UBYTE newname[128], oldname[128];
BPTR newfile;
DbMapLock(nim);
if ((nim->nim_Flags & NIMF_CHANGED) == 0)
goto exit;
newname[sizeof(newname)-1] = '\0';
strncpy(newname, nim->nim_Filename, sizeof(newname)-1);
strncat(newname, ".new", sizeof(newname)-1);
oldname[sizeof(oldname)-1] = '\0';
strncpy(oldname, nim->nim_Filename, sizeof(oldname)-1);
strncat(oldname, ".old", sizeof(oldname)-1);
if (newfile = Open(newname, MODE_NEWFILE)) {
struct Node *entry, *next;
retval = 0;
for (entry = nim->nim_Ent->lh_Head;
next = entry->ln_Succ;
entry = next) {
retval = Method(print_out, nim)(nid, newfile, (struct Ent *)entry);
if (retval)
break;
}
Close(newfile);
if (retval == 0) {
/* Now we are supposed to move newfile to file */
DeleteFile(oldname);
Rename(nim->nim_Filename, oldname);
if (Rename(newname, nim->nim_Filename))
nim->nim_Flags &= NIMF_CHANGED;
else
retval = NIERR_ACCESS;
}
} else {
retval = NIERR_ACCESS;
}
exit:
DbMapUnlock(nim);
}
req->io_Error = retval;
TermIO(req);
}
/*
* NI_MEMBERS
*/
void MembersCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
{
if (Method(membercmd, nim) != NULL) {
Method(membercmd, nim)(nid, req, nim);
} else {
req->io_Error = IOERR_NOCMD;
TermIO(req);
}
}
/*
* Find a pointer to this entry
*/
static struct NetInfoPointer *FindPointer(struct List *list, struct Ent *to)
{
struct NetInfoPointer *entry, *next;
for (entry = (struct NetInfoPointer *)list->lh_Head;
next = (struct NetInfoPointer *)entry->nip_Node->ln_Succ;
entry = next)
if (entry->nip_Ent == to) {
return entry;
}
return NULL;
}
/*
* Search for map
*/
struct NetInfoMap *CheckUnit(struct NetInfoDevice *nid, struct Unit *u)
{
struct NetInfoPointer *nip = (struct NetInfoPointer *)u;
if (nip != NULL)
return nip->nip_Map;
else
return NULL;
}
/*
* Parse group database if needed
*/
struct Ent *InternalSetEnts(struct NetInfoDevice *nid, struct NetInfoMap *nim)
{
DbMapLockShared(nim);
if ((nim->nim_Flags & NIMF_PARSED) == 0) {
int was_too_long = 0;
UBYTE *p, *line = NULL;
BPTR fh = NULL;
struct Ent *ent;
/* We can not get exclusive lock if we have shared lock */
DbMapUnlock(nim);
/* Exclusive lock for writing */
DbMapLock(nim);
if ((nim->nim_Flags & NIMF_PARSED) != 0)
goto error;
line = AllocVec(MAXLINELENGTH + 1, MEMF_PUBLIC);
fh = Open((STRPTR)nim->nim_Filename, MODE_OLDFILE);
if (!line || !fh)
goto error;
/* Free old entries */
FreeListVec(nid, nim->nim_Ent);
/* Invalidate pointers to old database */
ObtainSemaphore(nim->nim_PointerLock);
{
struct NetInfoPointer *nip, *next;
for (nip = (struct NetInfoPointer *)nim->nim_Pointer->lh_Head;
next = (struct NetInfoPointer *)nip->nip_Node->ln_Succ;
nip = next) {
nip->nip_Ent = NULL;
}
}
ReleaseSemaphore(nim->nim_PointerLock);
line[MAXLINELENGTH] = '\0';
while (p = FGets(fh, line, MAXLINELENGTH)) {
while (*p && *p != '\n')
p++;
if (!*p) {
/* Line is too long */
was_too_long = 1;
continue;
}
if (was_too_long) {
/* Rest of a line */
was_too_long = 0;
continue;
}
if (ent = Method(parse_ent, nim)(nid, line))
AddTail(nim->nim_Ent, (struct Node *)ent);
}
nim->nim_Flags |= NIMF_PARSED;
/* Ask for notifies */
if (nim->nim_Methods->notify != NULL &&
nim->nim_Notify->nr_UserData == 0) {
memset(nim->nim_Notify, 0, sizeof *nim->nim_Notify);
nim->nim_Notify->nr_Name = (STRPTR)nim->nim_Filename;
nim->nim_Notify->nr_Flags = NRF_SEND_MESSAGE;
nim->nim_Notify->nr_stuff.nr_Msg.nr_Port = nid->nid_NotifyPort;
nim->nim_Notify->nr_UserData = (IPTR) nim;
StartNotify(nim->nim_Notify);
}
error:
if (line) FreeVec(line);
if (fh) Close(fh);
/* Downgrade to a shared lock */
DbMapUnlock(nim);
DbMapLockShared(nim);
}
return (struct Ent *)nim->nim_Ent;
}
void InternalEndEnts(struct NetInfoDevice *nid, struct NetInfoMap *nim)
{
DbMapUnlock(nim);
}
/*
* Return next entry
*/
struct Ent *GetNextEnt(struct Ent *e)
{
e = (struct Ent *)e->e_node.ln_Succ;
if (e->e_node.ln_Succ)
return e;
else
return NULL;
}
/*
* Mark as unparsed (when map has received DOS notify)
*/
void EntHandleNotify(struct NetInfoDevice *nid, struct NetInfoMap *nim)
{
DbMapLockShared(nim);
nim->nim_Flags &= ~NIMF_PARSED;
DbMapUnlock(nim);
}
/*
* Free all entries
*/
void EntCleanup(struct NetInfoDevice *nid, struct NetInfoMap *nim)
{
DbMapLock(nim);
FreeListVec(nid, nim->nim_Ent);
/* End notifies */
if (nim->nim_Notify->nr_UserData != 0) {
EndNotify(nim->nim_Notify);
nim->nim_Notify->nr_UserData = 0;
}
DbMapUnlock(nim);
}