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