Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
	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
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
235
srvInit(void)
236
{
237
	sbox.lock = vtLockAlloc();
238
 
239
	cliAddCmd("srv", cmdSrv);
240
 
241
	return 1;
242
}