Plan 9 from Bell Labs’s /usr/web/sources/contrib/dho/nfil/src/9/ip/nfil.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#include "ip.h"

static void		nfil_append_hook(Nfil *, Nfil *, Nfil *, int);
static void		nfil_insert_hook(Nfil *, Nfil *, Nfil *, Nfil *, int);
static int		nfil_remove_hook(Nfil *, Nfil *, int);

Nfil *nfil_in_list;
Nfil *nfil_out_list;

void
nfil_init(void)
{
	print("Initializing nfil.\n");
	nfil_in_list = nil;
	nfil_out_list = nil;
}

int
nfil(Ipifc *ifc, Block *bp, int dir, void *xtra)
{
	Nfil *nlist;

	switch (dir) {
	case Direction_In:
		for(nlist = nfil_in_list; nlist != nil; nlist = nlist->next)
			if ((nlist->exec)(ifc, bp, xtra) == Nfil_Failure)
				return Nfil_Failure;
		break;
	case Direction_Out:
		for (nlist = nfil_out_list; nlist != nil; nlist = nlist->next)
			if ((nlist->exec)(ifc, bp, xtra) == Nfil_Failure)
				return Nfil_Failure;
		break;
	default:
		return Nfil_Failure;
	}

	return Nfil_Success;
}

int
nfil_register_hook(int (*fn)(Ipifc *, Block *, void *), int weight, int dir)
{
	Nfil *nl, *li, *si = nil, *head;

	if (fn == nil)
		return Nfil_Failure;

	/* XXX Should we panic? This could be a security issue. */
	if ((nl = malloc(sizeof(Nfil))) == nil)
		return Nfil_Failure;

	nl->exec = fn;
	nl->weight = weight;
	nl->tail = nil;

	if (dir == Direction_In)
		head = li = nfil_in_list;
	else
		head = li = nfil_out_list;

	/* We don't need to really do anything here except get to
	 * the right place in the list. Hooks with the same weight
	 * as one previously added will be executed in order of
	 * addition.
	 */
	for (; li != nil && li->weight <= weight; 
	    si = li, li = li->next) 
		weight = weight;

	/* Append function to list */
	if (li == nil) {
		nfil_append_hook(head, li, nl, dir);
	} else {
		/* We have to split the list to add the new weight */
		nfil_insert_hook(head, si, li, nl, dir);
	}

	print("Added hook with weight %d.\n", weight);

	return Nfil_Success;
}

int
nfil_unregister_hook(int (*exec)(Ipifc *, Block *, void *), int dir)
{
	Nfil *head, *before = nil;

	USED(before);

	if (dir == Direction_In)
		head = nfil_in_list;
	else
		head = nfil_out_list;

	for (; head->exec != exec; before = head, head = head->next) ;

	print("Removed hook");

	return nfil_remove_hook(before, head, dir);
}

static void
nfil_append_hook(Nfil *head, Nfil *li, Nfil *nl, int dir)
{
	/* It's possible that there is no list head */
	if (head == nil || li == nil) {
		if (dir == Direction_In)
			nfil_in_list = nl;
		else
			nfil_out_list = nl;
	} else {
		/* We're appending to an existing list */
		li->next = nl;
		nl->next = nil;
	}

	/* Update tail */
	if (dir == Direction_In)
		nfil_in_list->tail = nl;
	else
		nfil_out_list->tail = nl;
}

static void
nfil_insert_hook(Nfil *head, Nfil *sf, Nfil *sa, Nfil *nl, int dir)
{
	/* We're inserting before the head of the list */
	if (head == sf) {
		if (dir == Direction_In) {
			nfil_in_list = nl;
			nl->tail = head->tail;
		} else {
			nfil_out_list = nl;
			nl->tail = head->tail;
		}
		nl->next = sf;
	} else {
		sf->next = nl;
		nl->next = sa;
	}
}

static int
nfil_remove_hook(Nfil *remat, Nfil *rem, int dir)
{
	/* We're removing the head */
	if (remat == nil) {

		/* If this is the only entry in the list, just trash it */
		if (rem->next == nil) {
			free(rem);

			/* We need the direction to reset the head to nil */
			if (dir == Direction_In) nfil_in_list = nil;
			else nfil_out_list = nil;

			return Nfil_Success;
		}

		remat = malloc(sizeof(Nfil));
		if (remat == nil) 
			return Nfil_Failure;

		remat->tail = rem->tail;
	}

	remat->next = rem->next;
	free(rem);

	print("Appended hook\n");

	return Nfil_Success;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.