|
|
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 <utsname.h>
10: #include <pwd.h>
11: #include "dbtypes.h"
12:
13: /*
14: * system calls not in sysent.h
15: */
16: extern "C" int select(int, fd_set*, fd_set*, int);
17: #define WNOHANG 1 /* don't hang in wait */
18:
19: /*
20: * imported
21: */
22: extern "C" int detach(char *);
23: extern int optind;
24: extern char *optarg;
25: extern "C" int getopt(int, char *[], char *);
26: extern "C" long time(long *);
27: extern "C" int uname(utsname *);
28:
29: /*
30: * predeclared
31: */
32: int announce(int, char *);
33: int doset(int, char *, int *);
34: int dovalue(int, char *, char *, int *);
35: void dohelp(int);
36: void initclient();
37: void newclient(int);
38: void dropclient(int);
39: int clientreq(int);
40: Db *getdb(char *, int *);
41: void basefiles(char *, char *, char *, char **, char **);
42:
43: /*
44: * global
45: */
46: char *av0;
47: int debug;
48: char *locsysname = 0;
49:
50: /*
51: * return codes from clientreq
52: */
53: #define OK 0
54: #define DOPARSE 1
55: #define DROPCLIENT 2
56:
57: /*
58: * client data
59: */
60: fd_set cvec;
61: struct client {
62: int fd;
63: char *bp;
64: char *machine; /* Client's machine from ipcinfo (0 if local) */
65: char *user; /* Client's login from ipcinfo */
66: int dbhint; /* Hint for finding the needed user db */
67: } client[NOFILE];
68: int lastclient = -1;
69:
70: main(int ac, char *av[])
71: {
72: int i, n;
73: fd_set vec;
74: char errbuf[sizeof(Fbuffer)];
75: int doannounce, doparse;
76: char *mtpt = "ns";
77: int afd = -1;
78: long lastcheck = 0;
79: char *dbloadfile;
80: char *sysdbdir;
81: char *sysdbfile;
82: int dummyhint;
83: utsname utsn;
84: Db *sysdb;
85: int noparse = 0;
86:
87: av0 = av[0];
88: chdir("/cs");
89: dbloadfile = "/usr/ipc/lib/ns.db";
90:
91: /*
92: * parse arguments
93: */
94: while((i = getopt(ac, av, "dnm:f:")) != -1)
95: switch(i){
96: case 'd':
97: debug = 1;
98: break;
99: case 'm':
100: mtpt = optarg;
101: break;
102: case 'f':
103: dbloadfile = optarg;
104: break;
105: case 'n':
106: noparse = 1;
107: break;
108: }
109:
110: /*
111: * Don't die if pipe breaks
112: */
113:
114: signal(SIGPIPE, SIG_IGN);
115:
116: /*
117: * let go of the console
118: */
119: if(!debug)
120: detach(mtpt);
121:
122: /*
123: * Find out who we are and make the system name global
124: */
125: if (!uname(&utsn))
126: locsysname = utsn.sysname;
127:
128: Finit(2, errbuf);
129: initclient();
130:
131: /*
132: * Initialize system database and remember root system database
133: * file in sysdb structure
134: */
135:
136: basefiles("/usr/ipc/lib", "ns.db", dbloadfile, &sysdbdir, &sysdbfile);
137: sysdb = newdb((int *) 0, sysdbdir, sysdbfile, locsysname, &dummyhint);
138:
139: /*
140: * loop forever, announcing and listening for requests. We
141: * reannounce whenever a problem occurs with the announcement
142: * fd.
143: */
144: for(doannounce=doparse=1;;){
145: if(doannounce){
146: afd = announce(afd, mtpt);
147: doannounce = 0;
148: }
149: if(doparse || time((long *)0) - lastcheck > 8*60){
150: if (checkfiles(sysdb))
151: parsefiles(sysdb);
152: doparse = 0;
153: lastcheck = time((long *)0);
154: }
155: for(; !doannounce && !doparse;){
156: /*
157: * wait for a request
158: */
159: vec = cvec;
160: FD_SET(afd, vec);
161: switch(n=select(NOFILE, &vec, 0, 2*60*1000)){
162: case 0:
163: /*
164: * check to reparse if the system is
165: * quiescent
166: */
167: if(noparse == 0)
168: doparse = 1;
169: continue;
170: case -1:
171: doannounce = 1; /* all fd's bad */
172: continue;
173: }
174:
175: /*
176: * new client? A <0 return means that the
177: * announcement has gone sour.
178: */
179: if(FD_ISSET(afd, vec)){
180: n--;
181: newclient(afd);
182: }
183:
184: /*
185: * client request? A <0 return means the client
186: * has gone sour.
187: */
188: for(i=0; n>0 && i<NOFILE && client[i].fd>=0; i++){
189: if(FD_ISSET(client[i].fd, vec)){
190: n--;
191: switch(clientreq(i)){
192: case DROPCLIENT:
193: dropclient(i);
194: break;
195: case DOPARSE:
196: doparse = 1;
197: break;
198: }
199: }
200: }
201: }
202: }
203: }
204:
205: /*
206: * announce a service
207: */
208: announce(int afd, char *mtpt)
209: {
210: if(afd>=0)
211: close(afd);
212: sync();
213: for(afd=-1; afd<0; ){
214: afd = ipccreat(mtpt, "");
215: if(afd<0){
216: logconsole("%s: can't announce (%s)\n",av0,errstr);
217: sleep(10);
218: }
219: }
220: chmod(mtpt, 0666);
221: logconsole("%s: announced as %s\n", av0, mtpt);
222: return afd;
223: }
224:
225: /*
226: * Break infile into base directory and file in base directory. Use
227: * default directory for relative infile. Use default directory and
228: * default file if there's no infile.
229: */
230: void
231: basefiles(char *defdir, char *deffile, char *infile, char **basedir, char **file)
232: {
233: char *fileptr;
234:
235: if (fileptr= strrchr(infile,'/')) {
236: *fileptr = 0;
237: *file = strdup(fileptr + 1);
238: if (fileptr == infile)
239: *basedir = (char *) 0;
240: else if (*infile == '/')
241: *basedir = strdup(infile);
242: else
243: *basedir = strdup(path(infile,defdir));
244: *fileptr = '/';
245: } else if (infile && *infile) {
246: *file = strdup(infile);
247: *basedir = strdup(defdir);
248: } else {
249: *file = strdup(deffile);
250: *basedir = strdup(defdir);
251: }
252: }
253:
254: /*
255: * set all clients to off
256: */
257: void
258: initclient()
259: {
260: int i;
261:
262: for(i=0; i<NOFILE; i++)
263: client[i].fd = -1;
264: }
265:
266: void
267: ding(int x)
268: {
269: signal(SIGALRM, ding);
270: alarm(20);
271: }
272:
273: /*
274: * get a request for a new client
275: */
276: void
277: newclient(int fd)
278: {
279: int cfd;
280: int i;
281: ipcinfo *ip;
282:
283: /*
284: * since we're single stream, don't let listening for
285: * a call take forever. The alarm will abort any reads
286: * in ipclisten and ipcaccept.
287: */
288: signal(SIGALRM, ding);
289: alarm(20);
290: ip = ipclisten(fd);
291: if(ip==0)
292: return;
293: cfd = ipcaccept(ip);
294: alarm(0);
295: if(cfd<0)
296: return;
297: for(i=0; i<NOFILE; i++)
298: if(client[i].fd<0){
299: client[i].fd = cfd;
300: FD_SET(cfd, cvec);
301: if(i>lastclient)
302: lastclient = i;
303: if(!client[i].bp)
304: client[i].bp = malloc(sizeof(Fbuffer));
305: Finit(cfd, client[i].bp);
306: client[i].machine = 0;
307: if (ip->machine && *ip->machine)
308: client[i].machine = strdup(ip->machine);
309: client[i].user = strdup(ip->user);
310: client[i].dbhint = -1; /* no hint yet */
311: return;
312: }
313: close(cfd);
314: }
315:
316: /*
317: * drop a client
318: */
319: void
320: dropclient(int c)
321: {
322: /*
323: * close off this client
324: */
325: FD_CLR(client[c].fd, cvec);
326: close(client[c].fd);
327: client[c].fd = -1;
328: if (client[c].machine)
329: free(client[c].machine);
330: if (client[c].user)
331: free(client[c].user);
332:
333: /*
334: * move last client to this spot, lastclient may equal c
335: */
336: client[c] = client[lastclient];
337: client[lastclient].fd = -1;
338: lastclient--;
339: }
340:
341: /*
342: * service a client request
343: */
344: int
345: clientreq(int c)
346: {
347: char buf[512];
348: int n;
349: char *fields[3];
350: int fd = client[c].fd;
351:
352: /*
353: * read a line and split command and arguments
354: */
355: if((n=read(fd, buf, sizeof(buf)-1))<=0)
356: return DROPCLIENT;
357: buf[n] = '\0';
358: setfields(" \t\n");
359: n = getmfields(buf, fields, 2);
360: if(n<1) {
361: fprint(fd, "ILL null command\n");
362: return OK;
363: }
364:
365: /*
366: * act on command
367: */
368: if(fstrcmp("set", fields[0])==0){
369: if(n<2)
370: fprint(fd, "ILL no search key\n");
371: else
372: return doset(fd, fields[1], &client[c].dbhint);
373: } else if(fstrcmp("value", fields[0])==0) {
374: if(n<2) {
375: fprint(fd, "ILL no value types, no search key\n");
376: } else {
377: n = getmfields(fields[1], fields, 2);
378: if(n<2)
379: fprint(fd, "ILL no search key\n");
380: else
381: dovalue(fd,fields[0],fields[1],
382: &client[c].dbhint);
383: }
384: } else if(fstrcmp("help", fields[0])==0) {
385: dohelp(fd);
386: } else if(fstrcmp("quit", fields[0])==0) {
387: return DROPCLIENT;
388: } else if(fstrcmp("reset", fields[0])==0) {
389: Fprint(fd, "OK\n");
390: Fprint(fd, "DONE\n");
391: Fflush(fd);
392: logevent("reset by %s!%s\n",
393: (client[c].machine? client[c].machine:locsysname),
394: client[c].user);
395: releasedbs();
396: return DOPARSE;
397: } else
398: fprint(fd, "ILL\n");
399: return OK;
400: }
401:
402: /*
403: * Return a `set' of tuples matching allattributes in the request. The
404: * request is "set value[,type] value[,type] ..." The first valid attribute in
405: * the form: "system!login,db" is interpreted as the db to be searched.
406: * A request with no db attribute is resolved in the system db.
407: */
408: int
409: doset(int fd, char *key, int *hint)
410: {
411: Set *s = (Set *) 0;
412: int status;
413: Db *d;
414:
415: d = getdb(key,hint);
416: key = key + strspn(key, " \t\n");
417:
418: if (d)
419: s = lookup(key, d->o);
420:
421: if (Fprint(fd, "OK\n") < 0) {
422: if (s) delete s;
423: return DROPCLIENT;
424: }
425: if(s){
426: if(d->origin)
427: s->sort(d->origin->first);
428: status = s->print(fd);
429: delete s;
430: if (status < 0)
431: return DROPCLIENT;
432: }
433: if (Fprint(fd, "DONE\n") < 0)
434: return DROPCLIENT;
435: if (Fflush(fd) < 0)
436: return DROPCLIENT;
437: return 0;
438: }
439:
440: /*
441: * Return a single value. The value is of one of the types listed in
442: * the first argument of the request. The value comes from a tuple
443: * matching all attributes in the request. The request is
444: * "value type1|type2|type3|... value[,type] value[,type] ..."
445: * The first valid attribute in the form: "system!login,db" is
446: * interpreted as the db to be searched. A request with no db
447: * attribute is resolved in the system db.
448: */
449: int
450: dovalue(int fd, char *typelist, char *key, int *hint)
451: {
452: int n;
453: #define MAXTYPES 10
454: char *types[MAXTYPES+1];
455: Set *s;
456: Db *d;
457:
458: d = getdb(key,hint);
459: setfields("|");
460: n = getmfields(typelist, types, MAXTYPES);
461: if(n<=0) {
462: fprint(fd, "ILL bad types\n");
463: return -1;
464: }
465: types[MAXTYPES] = 0;
466:
467: if (d)
468: s = lookup(key, d->o);
469: Fprint(fd, "OK\n");
470: if(s){
471: if(d->origin)
472: s->sort(d->origin->first);
473: s->printvalue(fd, types);
474: delete s;
475: }
476: Fprint(fd, "DONE\n");
477: Fflush(fd);
478: return 0;
479: }
480:
481: /*
482: * return a usage menu
483: */
484: void
485: dohelp(int fd)
486: {
487: fprint(fd, "OK\n");
488: fprint(fd, "\tset value[,type] value[,type] ...\n");
489: fprint(fd, "\tvalue [type|type|]type value[,type] value[,type] ...\n");
490: fprint(fd, "\thelp\n");
491: fprint(fd, "\tquit\n");
492: fprint(fd, "\treset\n");
493: fprint(fd, "DONE\n");
494: }
495:
496: /*
497: * get the database to be used in resolving the query qstr. Qstr is modified
498: * to remove the db identifier. The db identifier can have any of the following
499: * forms:
500: * ,db : system database
501: * system,db : system database if system == locsysname
502: * !user,db : database in .nsrc file of login user
503: * system!user,db : same as !user,db if system == locsysname
504: * (none) : system database if no db attribute
505: *
506: * The first valid db attribute in qstr is used as the db identifier. If no
507: * db attribute is found, the system database is used. If only invalid attributes
508: * are found, no database is used, i.e. (Db *) 0 is returned.
509: */
510: Db *
511: getdb(char *qstr, int *hint)
512: {
513: char *commaloc;
514: char *dbname;
515: char *uname;
516: char *cp;
517: struct passwd *pw;
518: char failurepending = 0;
519: char dbnamebuf[MAXDBNAME+1];
520: Db *d;
521:
522: for (; commaloc = strchr(qstr, ','); qstr = commaloc + 1) {
523: if ((commaloc[1] == 'd') && (commaloc[2] == 'b') &&
524: ((commaloc[3]=='\n')||(commaloc[3]=='\t')||(commaloc[3]==' '))) {
525: *commaloc = 0;
526: for (dbname = commaloc - 1; dbname >= qstr; dbname--) {
527: if ((*dbname == '\t') || (*dbname == ' ')) {
528: dbname++;
529: break;
530: }
531: }
532: if (dbname < qstr)
533: dbname++;
534: if (dbname == commaloc) {
535: commaloc[0] = commaloc[1] = commaloc[2] = ' ';
536: break; /* System wildcard: ",db" */
537: }
538: uname = strchr(dbname,'!');
539: if (uname != dbname) {
540: if (uname)
541: *uname = 0;
542: if (fstrcmp(dbname, locsysname)) {
543: if (uname) *uname = '!';
544: *commaloc = ',';
545: failurepending = 1;
546: continue; /* System name differs */
547: }
548: if (!uname) {
549: for (cp = dbname; cp < commaloc + 3; cp++)
550: *cp = ' ';
551: break; /* Sys name matches: "system,db" */
552: }
553: *uname = '!';
554: }
555: if (pw = getpwnam(uname+1)) {
556: if (d = finddb(&pw->pw_uid, hint)) {
557: if (checkfiles(d))
558: parsefiles(d);
559: } else {
560: strncpy(dbnamebuf,locsysname,MAXDBNAME);
561: strncat(dbnamebuf,uname,MAXDBNAME);
562: d = newdb(&pw->pw_uid, pw->pw_dir,
563: ".nsrc", dbnamebuf, hint);
564: parsefiles(d);
565: }
566: for (cp = dbname; cp < commaloc + 3; cp++)
567: *cp = ' ';
568: return d; /* User name matches: */
569: /* "system!user,db" or "!user,db" */
570: }
571: *commaloc = ',';
572: failurepending = 1;
573: continue; /* User name differs */
574: }
575: qstr = commaloc + 1;
576: }
577: if (failurepending)
578: return (Db *) 0; /* No db field matched */
579:
580: return finddb((int *)0, hint); /* System name default */
581: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.