#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;
}
|