|
|
1.1 root 1: #include <sys/param.h>
2: #include <signal.h>
3: #include <sysent.h>
4: #include <libc.h>
5: #include <fio.h>
6: #include <ipc.h>
7: #include <string.h>
8: #include <errno.h>
9: #include "dbtypes.h"
10:
11: /*
12: * system calls not in sysent.h
13: */
14: extern "C" int select(int, fd_set*, fd_set*, int);
15: #define WNOHANG 1 /* don't hang in wait */
16:
17: /*
18: * imported
19: */
20: extern Ordered *parsefiles(char *, Ordered *);
21: extern "C" int detach(char *);
22: extern int optind;
23: extern char *optarg;
24: extern "C" int getopt(int, char *[], char *);
25: extern "C" long time(long *);
26:
27: /*
28: * predeclared
29: */
30: int announce(int, char *);
31: Ordered *parse(Set **, Ordered *);
32: int doset(int, char *, Ordered *, Set *);
33: int dovalue(int, char *, char *, Ordered *, Set *);
34: void dohelp(int);
35: void initclient();
36: void newclient(int);
37: void dropclient(int);
38: int clientreq(int, Ordered *, Set *);
39:
40: /*
41: * global
42: */
43: char *av0;
44: int debug;
45:
46: /*
47: * return codes from clientreq
48: */
49: #define OK 0
50: #define DOPARSE 1
51: #define DROPCLIENT 2
52:
53: /*
54: * client data
55: */
56: fd_set cvec;
57: struct client {
58: int fd;
59: char *bp;
60: } client[NOFILE];
61: int lastclient = -1;
62:
63: main(int ac, char *av[])
64: {
65: int i, n;
66: fd_set vec;
67: char errbuf[sizeof(Fbuffer)];
68: int doannounce, doparse;
69: Set *origin;
70: Ordered *o = 0;
71: char *mtpt = "ns";
72: int afd = -1;
73: long lastcheck = 0;
74:
75: av0 = av[0];
76: chdir("/cs");
77:
78: /*
79: * parse arguments
80: */
81: while((i = getopt(ac, av, "dm:")) != -1)
82: switch(i){
83: case 'd':
84: debug = 1;
85: break;
86: case 'm':
87: mtpt = optarg;
88: break;
89: }
90:
91: /*
92: * Don't die if pipe breaks
93: */
94:
95: signal(SIGPIPE, SIG_IGN);
96:
97: /*
98: * let go of the console
99: */
100: if(!debug)
101: detach(mtpt);
102: Finit(2, errbuf);
103: initclient();
104:
105: /*
106: * loop forever, announcing and listening for requests. We
107: * reannounce whenever a problem occurs with the announcement
108: * fd.
109: */
110: for(doannounce=doparse=1;;){
111: if(doannounce){
112: afd = announce(afd, mtpt);
113: doannounce = 0;
114: }
115: if(doparse || time((long *)0) - lastcheck > 8*60){
116: o = parse(&origin, o);
117: doparse = 0;
118: lastcheck = time((long *)0);
119: }
120:
121: for(; !doannounce && !doparse;){
122: /*
123: * wait for a request
124: */
125: vec = cvec;
126: FD_SET(afd, vec);
127: switch(n=select(NOFILE, &vec, 0, 2*60*1000)){
128: case 0:
129: /*
130: * check to reparse if the system is
131: * quiescent
132: */
133: doparse = 1;
134: continue;
135: case -1:
136: doannounce = 1; /* all fd's bad */
137: continue;
138: }
139:
140: /*
141: * new client? A <0 return means that the
142: * announcement has gone sour.
143: */
144: if(FD_ISSET(afd, vec)){
145: n--;
146: newclient(afd);
147: }
148:
149: /*
150: * client request? A <0 return means the client
151: * has gone sour.
152: */
153: for(i=0; n>0 && i<NOFILE && client[i].fd>=0; i++){
154: if(FD_ISSET(client[i].fd, vec)){
155: n--;
156: switch(clientreq(i, o, origin)){
157: case DROPCLIENT:
158: dropclient(i);
159: break;
160: case DOPARSE:
161: doparse = 1;
162: break;
163: }
164: }
165: }
166: }
167: }
168: }
169:
170: /*
171: * announce a service
172: */
173: announce(int afd, char *mtpt)
174: {
175: if(afd>=0)
176: close(afd);
177: sync();
178: for(afd=-1; afd<0; ){
179: afd = ipccreat(mtpt, "");
180: if(afd<0){
181: logconsole("%s: can't announce (%s)\n",av0,errstr);
182: sleep(10);
183: }
184: }
185: chmod(mtpt, 0666);
186: logconsole("%s: announced as %s\n", av0, mtpt);
187: return afd;
188: }
189:
190: /*
191: * parse database and return a skip list
192: */
193: Ordered *
194: parse(Set **origin, Ordered *o)
195: {
196: /*
197: * parse the database
198: */
199: o = parsefiles("ns.db", o);
200:
201: /*
202: * get the origin tuples
203: */
204: if(*origin)
205: delete *origin;
206: *origin = lookup("local,origin", o);
207: return o;
208: }
209:
210: /*
211: * set all clients to off
212: */
213: void
214: initclient()
215: {
216: int i;
217:
218: for(i=0; i<NOFILE; i++)
219: client[i].fd = -1;
220: }
221:
222: void
223: ding(int x)
224: {
225: signal(SIGALRM, ding);
226: alarm(20);
227: }
228:
229: /*
230: * get a request for a new client
231: */
232: void
233: newclient(int fd)
234: {
235: int cfd;
236: int i;
237: ipcinfo *ip;
238:
239: /*
240: * since we're single stream, don't let listening for
241: * a call take forever. The alarm will abort any reads
242: * in ipclisten and ipcaccept.
243: */
244: signal(SIGALRM, ding);
245: alarm(20);
246: ip = ipclisten(fd);
247: if(ip==0)
248: return;
249: cfd = ipcaccept(ip);
250: alarm(0);
251: if(cfd<0)
252: return;
253: for(i=0; i<NOFILE; i++)
254: if(client[i].fd<0){
255: client[i].fd = cfd;
256: FD_SET(cfd, cvec);
257: if(i>lastclient)
258: lastclient = i;
259: if(!client[i].bp)
260: client[i].bp = malloc(sizeof(Fbuffer));
261: Finit(cfd, client[i].bp);
262: return;
263: }
264: close(cfd);
265: }
266:
267: /*
268: * drop a client
269: */
270: void
271: dropclient(int c)
272: {
273: /*
274: * close off this client
275: */
276: FD_CLR(client[c].fd, cvec);
277: close(client[c].fd);
278: client[c].fd = -1;
279:
280: /*
281: * move last client to this spot, lastclient may equal c
282: */
283: client[c] = client[lastclient];
284: client[lastclient].fd = -1;
285: lastclient--;
286: }
287:
288: /*
289: * service a client request
290: */
291: int
292: clientreq(int c, Ordered *o, Set *origin)
293: {
294: char buf[512];
295: int n;
296: char *fields[3];
297: int fd = client[c].fd;
298:
299: /*
300: * read a line and split command and arguments
301: */
302: if((n=read(fd, buf, sizeof(buf)-1))<=0)
303: return DROPCLIENT;
304: buf[n] = '\0';
305: setfields(" \t\n");
306: n = getmfields(buf, fields, 2);
307: if(n<1) {
308: fprint(fd, "ILL null command\n");
309: return OK;
310: }
311:
312: /*
313: * act on command
314: */
315: if(fstrcmp("set", fields[0])==0){
316: if(n<2)
317: fprint(fd, "ILL no search key\n");
318: else
319: return doset(fd, fields[1], o, origin);
320: } else if(fstrcmp("value", fields[0])==0) {
321: if(n<2) {
322: fprint(fd, "ILL no value types, no search key\n");
323: } else {
324: n = getmfields(fields[1], fields, 2);
325: if(n<2)
326: fprint(fd, "ILL no search key\n");
327: else
328: dovalue(fd, fields[0], fields[1], o, origin);
329: }
330: } else if(fstrcmp("help", fields[0])==0) {
331: dohelp(fd);
332: } else if(fstrcmp("quit", fields[0])==0) {
333: return DROPCLIENT;
334: } else if(fstrcmp("reset", fields[0])==0) {
335: Fprint(fd, "OK\n");
336: Fprint(fd, "DONE\n");
337: Fflush(fd);
338: return DOPARSE;
339: } else
340: fprint(fd, "ILL\n");
341: return OK;
342: }
343:
344: /*
345: * Return a `set' of tuples matching allattributes in the request. The
346: * request is "set value[,type] value[,type] ..."
347: */
348: int
349: doset(int fd, char *key, Ordered *o, Set *origin)
350: {
351: Set *s;
352: int status;
353:
354: s = lookup(key, o);
355: if (Fprint(fd, "OK\n") < 0) {
356: if (s) delete s;
357: return DROPCLIENT;
358: }
359: if(s){
360: if(origin)
361: s->sort(origin->first);
362: status = s->print(fd);
363: delete s;
364: if (status < 0)
365: return DROPCLIENT;
366: }
367: if (Fprint(fd, "DONE\n") < 0)
368: return DROPCLIENT;
369: if (Fflush(fd) < 0)
370: return DROPCLIENT;
371: return 0;
372: }
373:
374: /*
375: * Return a single value. The value is of one of the types listed in
376: * the first argument of the request. The value comes from a tuple
377: * matching all attributes in the request. The request is
378: * "value type1|type2|type3|... value[,type] value[,type] ..."
379: */
380: int
381: dovalue(int fd, char *typelist, char *key, Ordered *o, Set *origin)
382: {
383: int n;
384: #define MAXTYPES 10
385: char *types[MAXTYPES+1];
386: Set *s;
387:
388: setfields("|");
389: n = getmfields(typelist, types, MAXTYPES);
390: if(n<=0) {
391: fprint(fd, "ILL bad types\n");
392: return -1;
393: }
394: types[MAXTYPES] = 0;
395:
396: s = lookup(key, o);
397: Fprint(fd, "OK\n");
398: if(s){
399: if(origin)
400: s->sort(origin->first);
401: s->printvalue(fd, types);
402: delete s;
403: }
404: Fprint(fd, "DONE\n");
405: Fflush(fd);
406: return 0;
407: }
408:
409: /*
410: * return a usage menu
411: */
412: void
413: dohelp(int fd)
414: {
415: fprint(fd, "OK\n");
416: fprint(fd, "\tset value[,type] value[,type] ...\n");
417: fprint(fd, "\tvalue [type|type|]type value[,type] value[,type] ...\n");
418: fprint(fd, "\thelp\n");
419: fprint(fd, "\tquit\n");
420: fprint(fd, "\treset\n");
421: fprint(fd, "DONE\n");
422: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.