xref: /plan9/sys/src/cmd/fossil/9srv.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include "stdinc.h"
2 
3 #include "9.h"
4 
5 typedef struct Srv Srv;
6 typedef struct Srv {
7 	int	fd;
8 	int	srvfd;
9 	char*	service;
10 	char*	mntpnt;
11 
12 	Srv*	next;
13 	Srv*	prev;
14 } Srv;
15 
16 static struct {
17 	VtLock*	lock;
18 
19 	Srv*	head;
20 	Srv*	tail;
21 } sbox;
22 
23 static int
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
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*
78 srvAlloc(char* service, int mode, int fd)
79 {
80 	Srv *srv;
81 	int srvfd;
82 	char *mntpnt;
83 
84 	vtLock(sbox.lock);
85 	for(srv = sbox.head; srv != nil; srv = srv->next){
86 		if(strcmp(srv->service, service) != 0)
87 			continue;
88 		vtSetError("srv: already serving '%s'", service);
89 		vtUnlock(sbox.lock);
90 		return nil;
91 	}
92 
93 	if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){
94 		vtUnlock(sbox.lock);
95 		return nil;
96 	}
97 	close(fd);
98 
99 	srv = vtMemAllocZ(sizeof(Srv));
100 	srv->srvfd = srvfd;
101 	srv->service = vtStrDup(service);
102 	srv->mntpnt = mntpnt;
103 
104 	if(sbox.tail != nil){
105 		srv->prev = sbox.tail;
106 		sbox.tail->next = srv;
107 	}
108 	else{
109 		sbox.head = srv;
110 		srv->prev = nil;
111 	}
112 	sbox.tail = srv;
113 	vtUnlock(sbox.lock);
114 
115 	return srv;
116 }
117 
118 static int
119 cmdSrv(int argc, char* argv[])
120 {
121 	Con *con;
122 	Srv *srv;
123 	char *usage = "usage: srv [-APWdp] [service]";
124 	int Aflag, Pflag, Wflag, dflag, fd[2], mode, pflag, r;
125 
126 	Aflag = Pflag = Wflag = dflag = pflag = 0;
127 	mode = 0666;
128 
129 	ARGBEGIN{
130 	default:
131 		return cliError(usage);
132 	case 'A':
133 		Aflag = 1;
134 		break;
135 	case 'P':
136 		Pflag = 1;
137 		mode = 0600;
138 		break;
139 	case 'W':
140 		Wflag = 1;
141 		mode = 0600;
142 		break;
143 	case 'd':
144 		dflag = 1;
145 		break;
146 	case 'p':
147 		pflag = 1;
148 		mode = 0600;
149 		break;
150 	}ARGEND
151 
152 	if(pflag && Pflag){
153 		vtSetError("srv: cannot use -P with -p");
154 		return 0;
155 	}
156 
157 	switch(argc){
158 	default:
159 		return cliError(usage);
160 	case 0:
161 		vtRLock(sbox.lock);
162 		for(srv = sbox.head; srv != nil; srv = srv->next)
163 			consPrint("\t%s\t%d\n", srv->service, srv->srvfd);
164 		vtRUnlock(sbox.lock);
165 
166 		return 1;
167 	case 1:
168 		if(!dflag)
169 			break;
170 
171 		vtLock(sbox.lock);
172 		for(srv = sbox.head; srv != nil; srv = srv->next){
173 			if(strcmp(srv->service, argv[0]) != 0)
174 				continue;
175 			srvFree(srv);
176 			break;
177 		}
178 		vtUnlock(sbox.lock);
179 
180 		if(srv == nil){
181 			vtSetError("srv: '%s' not found", argv[0]);
182 			return 0;
183 		}
184 
185 		return 1;
186 	}
187 
188 	if(pipe(fd) < 0){
189 		vtSetError("srv pipe: %r");
190 		return 0;
191 	}
192 	if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){
193 		close(fd[0]); close(fd[1]);
194 		return 0;
195 	}
196 
197 	if(pflag)
198 		r = consOpen(fd[1], srv->srvfd, -1);
199 	else{
200 		con = conAlloc(fd[1], srv->mntpnt);
201 		if(con == nil)
202 			r = 0;
203 		else{
204 			r = 1;
205 			con->noauth = Aflag;
206 			con->noperm = Pflag;
207 			con->wstatallow = Wflag;
208 		}
209 	}
210 	if(r == 0){
211 		close(fd[1]);
212 		vtLock(sbox.lock);
213 		srvFree(srv);
214 		vtUnlock(sbox.lock);
215 	}
216 
217 	return r;
218 }
219 
220 int
221 srvInit(void)
222 {
223 	sbox.lock = vtLockAlloc();
224 
225 	cliAddCmd("srv", cmdSrv);
226 
227 	return 1;
228 }
229