diff options
Diffstat (limited to 'src/cmd/fossil/9srv.c')
-rw-r--r-- | src/cmd/fossil/9srv.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/src/cmd/fossil/9srv.c b/src/cmd/fossil/9srv.c new file mode 100644 index 00000000..84696268 --- /dev/null +++ b/src/cmd/fossil/9srv.c @@ -0,0 +1,242 @@ +#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 { + VtLock* lock; + + Srv* head; + Srv* tail; +} sbox; + +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){ + vtMemFree(p); + p = smprint("#s/%s", name); + if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ + vtSetError("create %s: %r", p); + vtMemFree(p); + return -1; + } + } + + n = snprint(buf, sizeof(buf), "%d", fd); + if(write(srvfd, buf, n) < 0){ + close(srvfd); + vtSetError("write %s: %r", p); + vtMemFree(p); + return -1; + } + + *mntpnt = p; + + return srvfd; +} + +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); + vtMemFree(srv->service); + vtMemFree(srv->mntpnt); + vtMemFree(srv); +} + +static Srv* +srvAlloc(char* service, int mode, int fd) +{ + Dir *dir; + Srv *srv; + int srvfd; + char *mntpnt; + + vtLock(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); + vtSetError("srv: already serving '%s'", service); + vtUnlock(sbox.lock); + return nil; + } + srvFree(srv); + break; + } + + if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ + vtUnlock(sbox.lock); + return nil; + } + close(fd); + + srv = vtMemAllocZ(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; + vtUnlock(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)){ + vtSetError("srv: cannot use -P with -p"); + return 0; + } + + switch(argc){ + default: + return cliError(usage); + case 0: + vtRLock(sbox.lock); + for(srv = sbox.head; srv != nil; srv = srv->next) + consPrint("\t%s\t%d\n", srv->service, srv->srvfd); + vtRUnlock(sbox.lock); + + return 1; + case 1: + if(!dflag) + break; + + vtLock(sbox.lock); + for(srv = sbox.head; srv != nil; srv = srv->next){ + if(strcmp(srv->service, argv[0]) != 0) + continue; + srvFree(srv); + break; + } + vtUnlock(sbox.lock); + + if(srv == nil){ + vtSetError("srv: '%s' not found", argv[0]); + return 0; + } + + return 1; + } + + if(pipe(fd) < 0){ + vtSetError("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]); + vtLock(sbox.lock); + srvFree(srv); + vtUnlock(sbox.lock); + } + + return r; +} + +int +srvInit(void) +{ + sbox.lock = vtLockAlloc(); + + cliAddCmd("srv", cmdSrv); + + return 1; +} |