Plan 9 from Bell Labs’s /usr/web/sources/contrib/cinap_lenrek/old/linuxemu.old/util.c

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


#include <u.h>
#include <libc.h>
#include <ureg.h>
#include "linuxsys.h"
#include "linux.h"

typedef struct FdTag FdTag;
struct FdTag
{
	int fd;
	int tag;

	int open;
	int waitclose;

	// called if the tag is freed
	void (*destroy)(void *tag);
	void (*fork)(void *tag);

	FdTag *next;
	FdTag **link;

	void *data;
};

static Lock fdtagslock;
static FdTag *fdtags;

static FdTag *
findfdtag(int fd, int tag)
{
	FdTag *t;
	for(t=fdtags; t; t=t->next){
		if(fd>=0 && t->fd != fd)
			continue;
		if(tag!=TAG_ALL && t->tag!=tag)
			continue;
		return t;
	}
	return nil;
}

void
forkallfdtags(void)
{
	FdTag *t, *n;

	lock(&fdtagslock);
	for(t=fdtags; t; t=n){
		n = t->next;
		while(t->open){
			void *rendez;
			t->waitclose = 1;
			rendez = &t->waitclose;
			unlock(&fdtagslock);

			rendezvous(rendez, 0);

			lock(&fdtagslock);
		} 
		unlock(&fdtagslock);

		t->open = 1;
		forkfdtag(t);
		closefdtag(t);

		lock(&fdtagslock);
	}
	unlock(&fdtagslock);
}

static void
destroyalltags(void)
{
	void *tag;

	while(tag = openfdtag(-1, TAG_ALL, 0)){
		destroyfdtag(tag);
		closefdtag(tag);
	}
}

static int destroyalltagssetup = 0;

void *
openfdtag(int fd, int tag, int create)
{
	FdTag *t;
	void *rendez;

	if(!destroyalltagssetup){
		destroyalltagssetup=1;
		atexit(destroyalltags);
	}

	assert(fd >= 0 || !create);
	assert(tag!=TAG_ALL || !create);
	
again:
	lock(&fdtagslock);
	if(t = findfdtag(fd, tag))
		goto found;
	if(!create){
		unlock(&fdtagslock);
		return nil;
	}
	t = malloc(sizeof(FdTag));
	t->fd = fd;
	t->tag = tag;
	t->open = 0;
	t->waitclose = 0;
	t->data = nil;
	t->destroy = nil;
	t->fork = nil;
	if(t->next = fdtags)
		t->next->link = &t->next;
	t->link = &fdtags;
	*t->link = t;

	DPRINT("fdtag for fd %d tag %d was created...", t->fd, t->tag);
found:
	if(t->open){
		t->waitclose = 1;
		rendez = &t->waitclose;
	} else {
		t->open = 1;
		rendez = nil;
	} 
	unlock(&fdtagslock);

	if(rendez){
		rendezvous(rendez, 0);
		goto again;
	}
	return t;
}

void **
fdtagp(void *tag)
{
	FdTag *t;
	t = tag;
	assert(t->open);
	return &t->data;
}

int
fdtagfd(void *tag)
{
	FdTag *t;
	t = tag;
	assert(t->open);
	return t->fd;
}

void
atdestroyfdtag(void *tag, void (*destroy)(void *tag))
{
	FdTag *t;
	t = tag;
	assert(t->open);
	t->destroy = destroy;
}

void
atforkfdtag(void *tag, void (*fork)(void *tag))
{
	FdTag *t;
	t = tag;
	assert(t->open);
	t->fork = fork;
}

void
unlinkfdtag(void *tag)
{
	FdTag *t;
	t = tag;
	assert(t->open);
	lock(&fdtagslock);
	if(t->link){
		DPRINT("unlinking fdtag for fd %d tag %d...", t->fd, t->tag);
		if(t->next)
			t->next->link = t->link;
		*t->link = t->next;
		t->next = nil;
		t->link = nil;
	} else {
		DPRINT("fdtag for fd %d tag %d was already unlinked in unlinkfdtag()...", t->fd, t->tag);
	}
	unlock(&fdtagslock);
}

void
destroyfdtag(void *tag)
{
	FdTag *t;
	t = tag;
	assert(t->open);
	if(t->destroy){
		DPRINT("destroying fdtag for fd %d tag %d...", t->fd, t->tag);
		t->destroy(tag);
	}
	unlinkfdtag(tag);
}

void
forkfdtag(void *tag)
{
	FdTag *t;
	t = tag;
	assert(t->open);
	if(t->fork){
		DPRINT("forking fdtag for fd %d tag %d...", t->fd, t->tag);
		t->fork(tag);
	}
}

void
closefdtag(void *tag)
{
	FdTag *t;
	void *rendez;

	t = tag;
	assert(t->open);

	lock(&fdtagslock);
	if(t->waitclose){
		rendez = &t->waitclose;
		t->waitclose = 0;
	} else {
		rendez = nil;
	}
	t->open = 0;
	if(t->link == nil){
		DPRINT("fdtag for fd %d tag %d got unlinked...", t->fd, t->tag);
		free(t);
	}
	unlock(&fdtagslock);
	if(rendez)
		rendezvous(rendez, 0);
}

void
writeenv(char **env)
{
	while(*env){
		char name[256];
		char *f[2];
		char *e;
		int fd;

		e = strdup(*env++);
		if(getfields(e, f, 2, 1, "=")!=2){
			free(e);
			continue;
		}
		snprint(name, sizeof(name), "/env/%s", f[0]);
		if((fd = create(name, OWRITE, 0664)) >= 0){
			write(fd, f[1], strlen(f[1]));
			close(fd);
		}
		free(e);
	}
}

/*
 * readenv reads all files in /env and creates an enviroment char*[].
 * the entries itself are in the same memory block so it all can be freed 
 * without leaking memory.
 */
char **
readenv(char *buf, int nbuf)
{
	char **env;
	Dir *d;
	int fd, n, j, o;

	j = 0;
	n = 0;
	if((fd = open("/env", OREAD)) >= 0){
		d = nil;
		n = dirreadall(fd, &d);
		close(fd);
	}
	// o is the byteoffset for the string entries
	o = ((n+1)*sizeof(char*));

	// r is allocated bytes - guess the avarage size of the strings
	env = (char**)buf;

	if(n > 0){
		int a, i;

		// a counts used bytes for strings
		a = 0;
		for(i=0; i<n; i++){
			int m, l;
			char name[256];
			char *e;
			char *p;

			if(strstr(d[i].name, "fn#"))
				continue;
			if(strstr(d[i].name, "*"))
				continue;

			l = strlen(d[i].name);

			// calculate needed bytes for this entry
			m = l + 1 + d[i].length + 1;

			if(o + a + m > nbuf)
				break;

			e = (char*)env + o + a;

			p = e;

			// add key
			memcpy(p, d[i].name, l);
			p += l;
			*p++ = '=';

			// add value
			l = d[i].length;
			snprint(name, sizeof(name), "/env/%s", d[i].name);
			if((fd = open(name, OREAD)) < 0){
				continue;
			}
			if(readn(fd, p, l)!=l){
				close(fd);
				continue;
			}
			close(fd);
			p += l;

			*p = '\0';
			env[j++] = e;
			a += m;
		}
		free(d);
	}
	env[j] = nil;
	return env;
}

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.