|  | #include "stdinc.h" | 
|  |  | 
|  | #include "9.h" | 
|  |  | 
|  | typedef struct Srv Srv; | 
|  | struct Srv { | 
|  | int	fd; | 
|  | int	srvfd; | 
|  | char*	service; | 
|  | char*	mntpnt; | 
|  |  | 
|  | Srv*	next; | 
|  | Srv*	prev; | 
|  | }; | 
|  |  | 
|  | static struct { | 
|  | RWLock	lock; | 
|  |  | 
|  | Srv*	head; | 
|  | Srv*	tail; | 
|  | } sbox; | 
|  |  | 
|  | #ifndef PLAN9PORT | 
|  | static int | 
|  | srvFd(char* name, int mode, int fd, char** mntpnt) | 
|  | { | 
|  | int n, srvfd; | 
|  | char *p, buf[10]; | 
|  |  | 
|  | /* | 
|  | * Drop a file descriptor with given name and mode into /srv. | 
|  | * Create with ORCLOSE and don't close srvfd so it will be removed | 
|  | * automatically on process exit. | 
|  | */ | 
|  | p = smprint("/srv/%s", name); | 
|  | if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ | 
|  | vtfree(p); | 
|  | p = smprint("#s/%s", name); | 
|  | if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ | 
|  | werrstr("create %s: %r", p); | 
|  | vtfree(p); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | n = snprint(buf, sizeof(buf), "%d", fd); | 
|  | if(write(srvfd, buf, n) < 0){ | 
|  | close(srvfd); | 
|  | werrstr("write %s: %r", p); | 
|  | vtfree(p); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | *mntpnt = p; | 
|  |  | 
|  | return srvfd; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void | 
|  | srvFree(Srv* srv) | 
|  | { | 
|  | if(srv->prev != nil) | 
|  | srv->prev->next = srv->next; | 
|  | else | 
|  | sbox.head = srv->next; | 
|  | if(srv->next != nil) | 
|  | srv->next->prev = srv->prev; | 
|  | else | 
|  | sbox.tail = srv->prev; | 
|  |  | 
|  | if(srv->srvfd != -1) | 
|  | close(srv->srvfd); | 
|  | vtfree(srv->service); | 
|  | vtfree(srv->mntpnt); | 
|  | vtfree(srv); | 
|  | } | 
|  |  | 
|  | static Srv* | 
|  | srvAlloc(char* service, int mode, int fd) | 
|  | { | 
|  | Dir *dir; | 
|  | Srv *srv; | 
|  | int srvfd; | 
|  | char *mntpnt; | 
|  |  | 
|  | wlock(&sbox.lock); | 
|  | for(srv = sbox.head; srv != nil; srv = srv->next){ | 
|  | if(strcmp(srv->service, service) != 0) | 
|  | continue; | 
|  | /* | 
|  | * If the service exists, but is stale, | 
|  | * free it up and let the name be reused. | 
|  | */ | 
|  | if((dir = dirfstat(srv->srvfd)) != nil){ | 
|  | free(dir); | 
|  | werrstr("srv: already serving '%s'", service); | 
|  | wunlock(&sbox.lock); | 
|  | return nil; | 
|  | } | 
|  | srvFree(srv); | 
|  | break; | 
|  | } | 
|  |  | 
|  | #ifdef PLAN9PORT | 
|  | mntpnt = nil; | 
|  | if((srvfd = post9pservice(fd, service, mntpnt)) < 0){ | 
|  | #else | 
|  | if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ | 
|  | #endif | 
|  | wunlock(&sbox.lock); | 
|  | return nil; | 
|  | } | 
|  | close(fd); | 
|  |  | 
|  | srv = vtmallocz(sizeof(Srv)); | 
|  | srv->srvfd = srvfd; | 
|  | srv->service = vtstrdup(service); | 
|  | srv->mntpnt = mntpnt; | 
|  |  | 
|  | if(sbox.tail != nil){ | 
|  | srv->prev = sbox.tail; | 
|  | sbox.tail->next = srv; | 
|  | } | 
|  | else{ | 
|  | sbox.head = srv; | 
|  | srv->prev = nil; | 
|  | } | 
|  | sbox.tail = srv; | 
|  | wunlock(&sbox.lock); | 
|  |  | 
|  | return srv; | 
|  | } | 
|  |  | 
|  | static int | 
|  | cmdSrv(int argc, char* argv[]) | 
|  | { | 
|  | Con *con; | 
|  | Srv *srv; | 
|  | char *usage = "usage: srv [-APWdp] [service]"; | 
|  | int conflags, dflag, fd[2], mode, pflag, r; | 
|  |  | 
|  | dflag = 0; | 
|  | pflag = 0; | 
|  | conflags = 0; | 
|  | mode = 0666; | 
|  |  | 
|  | ARGBEGIN{ | 
|  | default: | 
|  | return cliError(usage); | 
|  | case 'A': | 
|  | conflags |= ConNoAuthCheck; | 
|  | break; | 
|  | case 'I': | 
|  | conflags |= ConIPCheck; | 
|  | break; | 
|  | case 'N': | 
|  | conflags |= ConNoneAllow; | 
|  | break; | 
|  | case 'P': | 
|  | conflags |= ConNoPermCheck; | 
|  | mode = 0600; | 
|  | break; | 
|  | case 'W': | 
|  | conflags |= ConWstatAllow; | 
|  | mode = 0600; | 
|  | break; | 
|  | case 'd': | 
|  | dflag = 1; | 
|  | break; | 
|  | case 'p': | 
|  | pflag = 1; | 
|  | mode = 0600; | 
|  | break; | 
|  | }ARGEND | 
|  |  | 
|  | if(pflag && (conflags&ConNoPermCheck)){ | 
|  | werrstr("srv: cannot use -P with -p"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | switch(argc){ | 
|  | default: | 
|  | return cliError(usage); | 
|  | case 0: | 
|  | rlock(&sbox.lock); | 
|  | for(srv = sbox.head; srv != nil; srv = srv->next) | 
|  | consPrint("\t%s\t%d\n", srv->service, srv->srvfd); | 
|  | runlock(&sbox.lock); | 
|  |  | 
|  | return 1; | 
|  | case 1: | 
|  | if(!dflag) | 
|  | break; | 
|  |  | 
|  | wlock(&sbox.lock); | 
|  | for(srv = sbox.head; srv != nil; srv = srv->next){ | 
|  | if(strcmp(srv->service, argv[0]) != 0) | 
|  | continue; | 
|  | srvFree(srv); | 
|  | break; | 
|  | } | 
|  | wunlock(&sbox.lock); | 
|  |  | 
|  | if(srv == nil){ | 
|  | werrstr("srv: '%s' not found", argv[0]); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | #ifdef PLAN9PORT	/* fossilcons unsupported */ | 
|  | if(pflag) | 
|  | return 1; | 
|  | #endif | 
|  |  | 
|  | if(pipe(fd) < 0){ | 
|  | werrstr("srv pipe: %r"); | 
|  | return 0; | 
|  | } | 
|  | if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ | 
|  | close(fd[0]); close(fd[1]); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(pflag) | 
|  | r = consOpen(fd[1], srv->srvfd, -1); | 
|  | else{ | 
|  | con = conAlloc(fd[1], srv->mntpnt, conflags); | 
|  | if(con == nil) | 
|  | r = 0; | 
|  | else | 
|  | r = 1; | 
|  | } | 
|  | if(r == 0){ | 
|  | close(fd[1]); | 
|  | wlock(&sbox.lock); | 
|  | srvFree(srv); | 
|  | wunlock(&sbox.lock); | 
|  | } | 
|  |  | 
|  | return r; | 
|  | } | 
|  |  | 
|  | int | 
|  | srvInit(void) | 
|  | { | 
|  | cliAddCmd("srv", cmdSrv); | 
|  |  | 
|  | return 1; | 
|  | } |