|
|
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.