aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/fossil/9srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/fossil/9srv.c')
-rw-r--r--src/cmd/fossil/9srv.c242
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;
+}