Blob


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