xref: /plan9/sys/src/cmd/fossil/9srv.c (revision e12a987081f10894b49298514b3a97b41db862b0)
1 #include "stdinc.h"
2 
3 #include "9.h"
4 
5 typedef struct Srv Srv;
6 struct Srv {
7 	int	fd;
8 	int	srvfd;
9 	char*	service;
10 	char*	mntpnt;
11 
12 	Srv*	next;
13 	Srv*	prev;
14 };
15 
16 static struct {
17 	VtLock*	lock;
18 
19 	Srv*	head;
20 	Srv*	tail;
21 } sbox;
22 
23 static int
srvFd(char * name,int mode,int fd,char ** mntpnt)24 srvFd(char* name, int mode, int fd, char** mntpnt)
25 {
26 	int n, srvfd;
27 	char *p, buf[10];
28 
29 	/*
30 	 * Drop a file descriptor with given name and mode into /srv.
31 	 * Create with ORCLOSE and don't close srvfd so it will be removed
32 	 * automatically on process exit.
33 	 */
34 	p = smprint("/srv/%s", name);
35 	if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){
36 		vtMemFree(p);
37 		p = smprint("#s/%s", name);
38 		if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){
39 			vtSetError("create %s: %r", p);
40 			vtMemFree(p);
41 			return -1;
42 		}
43 	}
44 
45 	n = snprint(buf, sizeof(buf), "%d", fd);
46 	if(write(srvfd, buf, n) < 0){
47 		close(srvfd);
48 		vtSetError("write %s: %r", p);
49 		vtMemFree(p);
50 		return -1;
51 	}
52 
53 	*mntpnt = p;
54 
55 	return srvfd;
56 }
57 
58 static void
srvFree(Srv * srv)59 srvFree(Srv* srv)
60 {
61 	if(srv->prev != nil)
62 		srv->prev->next = srv->next;
63 	else
64 		sbox.head = srv->next;
65 	if(srv->next != nil)
66 		srv->next->prev = srv->prev;
67 	else
68 		sbox.tail = srv->prev;
69 
70 	if(srv->srvfd != -1)
71 		close(srv->srvfd);
72 	vtMemFree(srv->service);
73 	vtMemFree(srv->mntpnt);
74 	vtMemFree(srv);
75 }
76 
77 static Srv*
srvAlloc(char * service,int mode,int fd)78 srvAlloc(char* service, int mode, int fd)
79 {
80 	Dir *dir;
81 	Srv *srv;
82 	int srvfd;
83 	char *mntpnt;
84 
85 	vtLock(sbox.lock);
86 	for(srv = sbox.head; srv != nil; srv = srv->next){
87 		if(strcmp(srv->service, service) != 0)
88 			continue;
89 		/*
90 		 * If the service exists, but is stale,
91 		 * free it up and let the name be reused.
92 		 */
93 		if((dir = dirfstat(srv->srvfd)) != nil){
94 			free(dir);
95 			vtSetError("srv: already serving '%s'", service);
96 			vtUnlock(sbox.lock);
97 			return nil;
98 		}
99 		srvFree(srv);
100 		break;
101 	}
102 
103 	if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){
104 		vtUnlock(sbox.lock);
105 		return nil;
106 	}
107 	close(fd);
108 
109 	srv = vtMemAllocZ(sizeof(Srv));
110 	srv->srvfd = srvfd;
111 	srv->service = vtStrDup(service);
112 	srv->mntpnt = mntpnt;
113 
114 	if(sbox.tail != nil){
115 		srv->prev = sbox.tail;
116 		sbox.tail->next = srv;
117 	}
118 	else{
119 		sbox.head = srv;
120 		srv->prev = nil;
121 	}
122 	sbox.tail = srv;
123 	vtUnlock(sbox.lock);
124 
125 	return srv;
126 }
127 
128 static int
cmdSrv(int argc,char * argv[])129 cmdSrv(int argc, char* argv[])
130 {
131 	Con *con;
132 	Srv *srv;
133 	char *usage = "usage: srv [-APWdp] [service]";
134 	int conflags, dflag, fd[2], mode, pflag, r;
135 
136 	dflag = 0;
137 	pflag = 0;
138 	conflags = 0;
139 	mode = 0666;
140 
141 	ARGBEGIN{
142 	default:
143 		return cliError(usage);
144 	case 'A':
145 		conflags |= ConNoAuthCheck;
146 		break;
147 	case 'I':
148 		conflags |= ConIPCheck;
149 		break;
150 	case 'N':
151 		conflags |= ConNoneAllow;
152 		break;
153 	case 'P':
154 		conflags |= ConNoPermCheck;
155 		mode = 0600;
156 		break;
157 	case 'W':
158 		conflags |= ConWstatAllow;
159 		mode = 0600;
160 		break;
161 	case 'd':
162 		dflag = 1;
163 		break;
164 	case 'p':
165 		pflag = 1;
166 		mode = 0600;
167 		break;
168 	}ARGEND
169 
170 	if(pflag && (conflags&ConNoPermCheck)){
171 		vtSetError("srv: cannot use -P with -p");
172 		return 0;
173 	}
174 
175 	switch(argc){
176 	default:
177 		return cliError(usage);
178 	case 0:
179 		vtRLock(sbox.lock);
180 		for(srv = sbox.head; srv != nil; srv = srv->next)
181 			consPrint("\t%s\t%d\n", srv->service, srv->srvfd);
182 		vtRUnlock(sbox.lock);
183 
184 		return 1;
185 	case 1:
186 		if(!dflag)
187 			break;
188 
189 		vtLock(sbox.lock);
190 		for(srv = sbox.head; srv != nil; srv = srv->next){
191 			if(strcmp(srv->service, argv[0]) != 0)
192 				continue;
193 			srvFree(srv);
194 			break;
195 		}
196 		vtUnlock(sbox.lock);
197 
198 		if(srv == nil){
199 			vtSetError("srv: '%s' not found", argv[0]);
200 			return 0;
201 		}
202 
203 		return 1;
204 	}
205 
206 	if(pipe(fd) < 0){
207 		vtSetError("srv pipe: %r");
208 		return 0;
209 	}
210 	if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){
211 		close(fd[0]); close(fd[1]);
212 		return 0;
213 	}
214 
215 	if(pflag)
216 		r = consOpen(fd[1], srv->srvfd, -1);
217 	else{
218 		con = conAlloc(fd[1], srv->mntpnt, conflags);
219 		if(con == nil)
220 			r = 0;
221 		else
222 			r = 1;
223 	}
224 	if(r == 0){
225 		close(fd[1]);
226 		vtLock(sbox.lock);
227 		srvFree(srv);
228 		vtUnlock(sbox.lock);
229 	}
230 
231 	return r;
232 }
233 
234 int
srvInit(void)235 srvInit(void)
236 {
237 	sbox.lock = vtLockAlloc();
238 
239 	cliAddCmd("srv", cmdSrv);
240 
241 	return 1;
242 }
243