xref: /plan9/sys/src/cmd/fossil/9srv.c (revision e12a987081f10894b49298514b3a97b41db862b0)
15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier 
35e96a66cSDavid du Colombier #include "9.h"
45e96a66cSDavid du Colombier 
55e96a66cSDavid du Colombier typedef struct Srv Srv;
6*e12a9870SDavid du Colombier struct Srv {
75e96a66cSDavid du Colombier 	int	fd;
85e96a66cSDavid du Colombier 	int	srvfd;
95e96a66cSDavid du Colombier 	char*	service;
105e96a66cSDavid du Colombier 	char*	mntpnt;
115e96a66cSDavid du Colombier 
125e96a66cSDavid du Colombier 	Srv*	next;
135e96a66cSDavid du Colombier 	Srv*	prev;
14*e12a9870SDavid du Colombier };
155e96a66cSDavid du Colombier 
165e96a66cSDavid du Colombier static struct {
175e96a66cSDavid du Colombier 	VtLock*	lock;
185e96a66cSDavid du Colombier 
195e96a66cSDavid du Colombier 	Srv*	head;
205e96a66cSDavid du Colombier 	Srv*	tail;
215e96a66cSDavid du Colombier } sbox;
225e96a66cSDavid du Colombier 
235e96a66cSDavid du Colombier static int
srvFd(char * name,int mode,int fd,char ** mntpnt)2434e04225SDavid du Colombier srvFd(char* name, int mode, int fd, char** mntpnt)
255e96a66cSDavid du Colombier {
265e96a66cSDavid du Colombier 	int n, srvfd;
2734e04225SDavid du Colombier 	char *p, buf[10];
285e96a66cSDavid du Colombier 
295e96a66cSDavid du Colombier 	/*
305e96a66cSDavid du Colombier 	 * Drop a file descriptor with given name and mode into /srv.
315e96a66cSDavid du Colombier 	 * Create with ORCLOSE and don't close srvfd so it will be removed
325e96a66cSDavid du Colombier 	 * automatically on process exit.
335e96a66cSDavid du Colombier 	 */
3434e04225SDavid du Colombier 	p = smprint("/srv/%s", name);
3534e04225SDavid du Colombier 	if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){
3634e04225SDavid du Colombier 		vtMemFree(p);
3734e04225SDavid du Colombier 		p = smprint("#s/%s", name);
3834e04225SDavid du Colombier 		if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){
3934e04225SDavid du Colombier 			vtSetError("create %s: %r", p);
4034e04225SDavid du Colombier 			vtMemFree(p);
415e96a66cSDavid du Colombier 			return -1;
425e96a66cSDavid du Colombier 		}
435e96a66cSDavid du Colombier 	}
445e96a66cSDavid du Colombier 
455e96a66cSDavid du Colombier 	n = snprint(buf, sizeof(buf), "%d", fd);
465e96a66cSDavid du Colombier 	if(write(srvfd, buf, n) < 0){
475e96a66cSDavid du Colombier 		close(srvfd);
4834e04225SDavid du Colombier 		vtSetError("write %s: %r", p);
4934e04225SDavid du Colombier 		vtMemFree(p);
505e96a66cSDavid du Colombier 		return -1;
515e96a66cSDavid du Colombier 	}
525e96a66cSDavid du Colombier 
5334e04225SDavid du Colombier 	*mntpnt = p;
5434e04225SDavid du Colombier 
555e96a66cSDavid du Colombier 	return srvfd;
565e96a66cSDavid du Colombier }
575e96a66cSDavid du Colombier 
585e96a66cSDavid du Colombier static void
srvFree(Srv * srv)595e96a66cSDavid du Colombier srvFree(Srv* srv)
605e96a66cSDavid du Colombier {
615e96a66cSDavid du Colombier 	if(srv->prev != nil)
625e96a66cSDavid du Colombier 		srv->prev->next = srv->next;
635e96a66cSDavid du Colombier 	else
645e96a66cSDavid du Colombier 		sbox.head = srv->next;
655e96a66cSDavid du Colombier 	if(srv->next != nil)
665e96a66cSDavid du Colombier 		srv->next->prev = srv->prev;
675e96a66cSDavid du Colombier 	else
685e96a66cSDavid du Colombier 		sbox.tail = srv->prev;
695e96a66cSDavid du Colombier 
705e96a66cSDavid du Colombier 	if(srv->srvfd != -1)
715e96a66cSDavid du Colombier 		close(srv->srvfd);
725e96a66cSDavid du Colombier 	vtMemFree(srv->service);
735e96a66cSDavid du Colombier 	vtMemFree(srv->mntpnt);
745e96a66cSDavid du Colombier 	vtMemFree(srv);
755e96a66cSDavid du Colombier }
765e96a66cSDavid du Colombier 
775e96a66cSDavid du Colombier static Srv*
srvAlloc(char * service,int mode,int fd)785e96a66cSDavid du Colombier srvAlloc(char* service, int mode, int fd)
795e96a66cSDavid du Colombier {
80ceddb3d7SDavid du Colombier 	Dir *dir;
815e96a66cSDavid du Colombier 	Srv *srv;
825e96a66cSDavid du Colombier 	int srvfd;
8334e04225SDavid du Colombier 	char *mntpnt;
845e96a66cSDavid du Colombier 
855e96a66cSDavid du Colombier 	vtLock(sbox.lock);
865e96a66cSDavid du Colombier 	for(srv = sbox.head; srv != nil; srv = srv->next){
875e96a66cSDavid du Colombier 		if(strcmp(srv->service, service) != 0)
885e96a66cSDavid du Colombier 			continue;
89ceddb3d7SDavid du Colombier 		/*
90ceddb3d7SDavid du Colombier 		 * If the service exists, but is stale,
91ceddb3d7SDavid du Colombier 		 * free it up and let the name be reused.
92ceddb3d7SDavid du Colombier 		 */
93ceddb3d7SDavid du Colombier 		if((dir = dirfstat(srv->srvfd)) != nil){
94ceddb3d7SDavid du Colombier 			free(dir);
955e96a66cSDavid du Colombier 			vtSetError("srv: already serving '%s'", service);
965e96a66cSDavid du Colombier 			vtUnlock(sbox.lock);
975e96a66cSDavid du Colombier 			return nil;
985e96a66cSDavid du Colombier 		}
99ceddb3d7SDavid du Colombier 		srvFree(srv);
100ceddb3d7SDavid du Colombier 		break;
101ceddb3d7SDavid du Colombier 	}
1025e96a66cSDavid du Colombier 
10334e04225SDavid du Colombier 	if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){
1045e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
1055e96a66cSDavid du Colombier 		return nil;
1065e96a66cSDavid du Colombier 	}
1075e96a66cSDavid du Colombier 	close(fd);
1085e96a66cSDavid du Colombier 
1095e96a66cSDavid du Colombier 	srv = vtMemAllocZ(sizeof(Srv));
1105e96a66cSDavid du Colombier 	srv->srvfd = srvfd;
1115e96a66cSDavid du Colombier 	srv->service = vtStrDup(service);
11234e04225SDavid du Colombier 	srv->mntpnt = mntpnt;
1135e96a66cSDavid du Colombier 
1145e96a66cSDavid du Colombier 	if(sbox.tail != nil){
1155e96a66cSDavid du Colombier 		srv->prev = sbox.tail;
1165e96a66cSDavid du Colombier 		sbox.tail->next = srv;
1175e96a66cSDavid du Colombier 	}
1185e96a66cSDavid du Colombier 	else{
1195e96a66cSDavid du Colombier 		sbox.head = srv;
1205e96a66cSDavid du Colombier 		srv->prev = nil;
1215e96a66cSDavid du Colombier 	}
1225e96a66cSDavid du Colombier 	sbox.tail = srv;
1235e96a66cSDavid du Colombier 	vtUnlock(sbox.lock);
1245e96a66cSDavid du Colombier 
1255e96a66cSDavid du Colombier 	return srv;
1265e96a66cSDavid du Colombier }
1275e96a66cSDavid du Colombier 
1285e96a66cSDavid du Colombier static int
cmdSrv(int argc,char * argv[])1295e96a66cSDavid du Colombier cmdSrv(int argc, char* argv[])
1305e96a66cSDavid du Colombier {
131dc5a79c1SDavid du Colombier 	Con *con;
132d58da526SDavid du Colombier 	Srv *srv;
133d58da526SDavid du Colombier 	char *usage = "usage: srv [-APWdp] [service]";
1342cca75a1SDavid du Colombier 	int conflags, dflag, fd[2], mode, pflag, r;
1355e96a66cSDavid du Colombier 
1362cca75a1SDavid du Colombier 	dflag = 0;
1372cca75a1SDavid du Colombier 	pflag = 0;
1382cca75a1SDavid du Colombier 	conflags = 0;
1395e96a66cSDavid du Colombier 	mode = 0666;
1405e96a66cSDavid du Colombier 
1415e96a66cSDavid du Colombier 	ARGBEGIN{
1425e96a66cSDavid du Colombier 	default:
1435e96a66cSDavid du Colombier 		return cliError(usage);
144dc5a79c1SDavid du Colombier 	case 'A':
1452cca75a1SDavid du Colombier 		conflags |= ConNoAuthCheck;
1462cca75a1SDavid du Colombier 		break;
1472cca75a1SDavid du Colombier 	case 'I':
1482cca75a1SDavid du Colombier 		conflags |= ConIPCheck;
1492cca75a1SDavid du Colombier 		break;
1502cca75a1SDavid du Colombier 	case 'N':
1512cca75a1SDavid du Colombier 		conflags |= ConNoneAllow;
152dc5a79c1SDavid du Colombier 		break;
153d58da526SDavid du Colombier 	case 'P':
1542cca75a1SDavid du Colombier 		conflags |= ConNoPermCheck;
155d58da526SDavid du Colombier 		mode = 0600;
156d58da526SDavid du Colombier 		break;
157d58da526SDavid du Colombier 	case 'W':
1582cca75a1SDavid du Colombier 		conflags |= ConWstatAllow;
159d58da526SDavid du Colombier 		mode = 0600;
160d58da526SDavid du Colombier 		break;
1615e96a66cSDavid du Colombier 	case 'd':
1625e96a66cSDavid du Colombier 		dflag = 1;
1635e96a66cSDavid du Colombier 		break;
1645e96a66cSDavid du Colombier 	case 'p':
1655e96a66cSDavid du Colombier 		pflag = 1;
1665e96a66cSDavid du Colombier 		mode = 0600;
1675e96a66cSDavid du Colombier 		break;
1685e96a66cSDavid du Colombier 	}ARGEND
1695e96a66cSDavid du Colombier 
1702cca75a1SDavid du Colombier 	if(pflag && (conflags&ConNoPermCheck)){
171dc5a79c1SDavid du Colombier 		vtSetError("srv: cannot use -P with -p");
172dc5a79c1SDavid du Colombier 		return 0;
173dc5a79c1SDavid du Colombier 	}
174dc5a79c1SDavid du Colombier 
1755e96a66cSDavid du Colombier 	switch(argc){
1765e96a66cSDavid du Colombier 	default:
1775e96a66cSDavid du Colombier 		return cliError(usage);
1785e96a66cSDavid du Colombier 	case 0:
1795e96a66cSDavid du Colombier 		vtRLock(sbox.lock);
1805e96a66cSDavid du Colombier 		for(srv = sbox.head; srv != nil; srv = srv->next)
1815e96a66cSDavid du Colombier 			consPrint("\t%s\t%d\n", srv->service, srv->srvfd);
1825e96a66cSDavid du Colombier 		vtRUnlock(sbox.lock);
1835e96a66cSDavid du Colombier 
1845e96a66cSDavid du Colombier 		return 1;
1855e96a66cSDavid du Colombier 	case 1:
1865e96a66cSDavid du Colombier 		if(!dflag)
1875e96a66cSDavid du Colombier 			break;
1885e96a66cSDavid du Colombier 
1895e96a66cSDavid du Colombier 		vtLock(sbox.lock);
1905e96a66cSDavid du Colombier 		for(srv = sbox.head; srv != nil; srv = srv->next){
1915e96a66cSDavid du Colombier 			if(strcmp(srv->service, argv[0]) != 0)
1925e96a66cSDavid du Colombier 				continue;
1935e96a66cSDavid du Colombier 			srvFree(srv);
1945e96a66cSDavid du Colombier 			break;
1955e96a66cSDavid du Colombier 		}
1965e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
1975e96a66cSDavid du Colombier 
1985e96a66cSDavid du Colombier 		if(srv == nil){
1995e96a66cSDavid du Colombier 			vtSetError("srv: '%s' not found", argv[0]);
2005e96a66cSDavid du Colombier 			return 0;
2015e96a66cSDavid du Colombier 		}
2025e96a66cSDavid du Colombier 
2035e96a66cSDavid du Colombier 		return 1;
2045e96a66cSDavid du Colombier 	}
2055e96a66cSDavid du Colombier 
2065e96a66cSDavid du Colombier 	if(pipe(fd) < 0){
2075e96a66cSDavid du Colombier 		vtSetError("srv pipe: %r");
2085e96a66cSDavid du Colombier 		return 0;
2095e96a66cSDavid du Colombier 	}
2105e96a66cSDavid du Colombier 	if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){
2115e96a66cSDavid du Colombier 		close(fd[0]); close(fd[1]);
2125e96a66cSDavid du Colombier 		return 0;
2135e96a66cSDavid du Colombier 	}
2145e96a66cSDavid du Colombier 
2155e96a66cSDavid du Colombier 	if(pflag)
2165e96a66cSDavid du Colombier 		r = consOpen(fd[1], srv->srvfd, -1);
217dc5a79c1SDavid du Colombier 	else{
2182cca75a1SDavid du Colombier 		con = conAlloc(fd[1], srv->mntpnt, conflags);
219dc5a79c1SDavid du Colombier 		if(con == nil)
220dc5a79c1SDavid du Colombier 			r = 0;
2212cca75a1SDavid du Colombier 		else
222dc5a79c1SDavid du Colombier 			r = 1;
223dc5a79c1SDavid du Colombier 	}
2245e96a66cSDavid du Colombier 	if(r == 0){
2255e96a66cSDavid du Colombier 		close(fd[1]);
2265e96a66cSDavid du Colombier 		vtLock(sbox.lock);
2275e96a66cSDavid du Colombier 		srvFree(srv);
2285e96a66cSDavid du Colombier 		vtUnlock(sbox.lock);
2295e96a66cSDavid du Colombier 	}
2305e96a66cSDavid du Colombier 
2315e96a66cSDavid du Colombier 	return r;
2325e96a66cSDavid du Colombier }
2335e96a66cSDavid du Colombier 
2345e96a66cSDavid du Colombier int
srvInit(void)2355e96a66cSDavid du Colombier srvInit(void)
2365e96a66cSDavid du Colombier {
2375e96a66cSDavid du Colombier 	sbox.lock = vtLockAlloc();
2385e96a66cSDavid du Colombier 
2395e96a66cSDavid du Colombier 	cliAddCmd("srv", cmdSrv);
2405e96a66cSDavid du Colombier 
2415e96a66cSDavid du Colombier 	return 1;
2425e96a66cSDavid du Colombier }
243