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