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