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