QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 1 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 1 /* qi.c - UIUC CCSO nameserver query interpreter */ 2 /* Bruce Tanner - Cerritos College */ 3 4 /* Version history: */ 5 /* 1.0 1993/08/15 Initial version */ 6 /* 1.1 1993/08/25 Add field instance attribute, conditionalize options */ 7 8 9 #include stdio 271 #include string 317 #include ctype 380 #include ssdef 1022 #include descrip 1455 #include time 1572 #include stdarg 1601 #include rms 4167 #include "qi.h" 4263 4264 4265 Fields fields[MAX_FIELD]; /* field attributes, global */ 4266 int debug; /* user requested debug */ 4267 extern int db_status; /* status of database */ 4268 4269 void db_open(); 4270 void db_close(); 4271 int read_fields(char *); 4272 int fields_cmd(char *, int); 4273 char *new_string(char *); 4274 char *getlogical(char *); 4275 void qilog(int, char *, ...); 4276 extern int query(char *, int); 4277 int quit(char *, int); 4278 Arg *parse_cmd(char *, int); 4279 Arg *make_arg(char *, int, char *, int); 4280 void free_args(Arg *); 4281 void writestring(int, char *); 4282 void qiabort(int, char *); 4283 int id_cmd(char *, int); 4284 int stat_cmd(char *, int); 4285 int set_cmd(char *, int); 4286 int site_cmd(char *, int); 4287 4288 struct verb_struct { 4289 char *name; 4290 int mode; /* requires login, etc */ 4291 int (*proc)(char *, int); 4292 } verbs[] = {{"quit", 0, quit}, 4293 {"stop", 0, quit}, 4294 {"exit", 0, quit}, 4295 {"fields", 0, fields_cmd}, 4296 {"query", 0, query}, 4297 {"ph", 0, query}, 4298 {"status", 0, stat_cmd}, 4299 {"id", 0, id_cmd}, 4300 {"set", 0, set_cmd}, QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 2 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4301 {"siteinfo", 0, site_cmd} 4302 }; 4303 4304 #define MAX_VERBS (sizeof(verbs) / sizeof(struct verb_struct)) 4305 4306 4307 4308 /* This program is designed to run as an 'inetd' detached process */ 4309 4310 main() 4311 { 4312 1 int status, sock; 4313 1 unsigned short chan; 4314 1 $DESCRIPTOR(sysin_dsc, "SYS$INPUT"); 4315 1 4316 1 /* open a channel to an INET device */ 4317 1 status = sys$assign(&sysin_dsc, &chan, 0, 0, 0); 4318 1 if ((status & 1) != SS$_NORMAL) { 4319 2 qilog(-1, "Open fail status = %d", status); 4320 2 exit(status); 4321 2 } 4322 1 sock = (int) chan; 4323 1 4324 1 /* load fields */ 4325 1 if (read_fields(getlogical(CONFIG_NAME)) == False) 4326 1 exit(4); 4327 1 4328 1 db_open(); 4329 1 while (process(sock)); 4330 1 closenet(sock); 4331 1 db_close(); 4332 1 } 4333 4334 4335 /* process a command stream */ 4336 4337 int process(int sock) 4338 { 4339 1 int status, ind, length; 4340 1 static int bad_cmd = 0; 4341 1 char *cp, inputline[MAX_INPUT]; 4342 1 4343 1 strncpy(inputline, "", MAX_INPUT); 4344 1 length = readline(sock, inputline, MAX_INPUT); /** Get the line **/ 4345 1 ZapCRLF(inputline); 4346 1 qilog(sock, "Cmd: %s", inputline); 4347 1 4348 1 if (length <= 0) { 4349 2 qilog(sock, "Remote end shutdown"); 4350 2 return False; 4351 2 } 4352 1 4353 1 if (strlen(inputline) == 0) /* ignore blank lines */ 4354 1 if (++bad_cmd > MAX_BAD) 4355 1 return False; /* too many null commands */ 4356 1 else 4357 1 return True; QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 3 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4358 1 4359 1 /* everything assumes lower case input; make it so */ 4360 1 for (cp = inputline; *cp; cp++) *cp = _tolower(*cp); 4361 1 4362 1 for (ind = 0; ind < MAX_VERBS; ind++) 4363 1 if (strncmp(inputline, verbs[ind].name, 4364 1 strlen(verbs[ind].name)) == 0) { 4365 2 status = (*verbs[ind].proc)(inputline, sock); 4366 2 break; 4367 2 } 4368 1 if (ind == MAX_VERBS) { 4369 2 qilog(sock, "Unknown command: /%s/", inputline); 4370 2 writestring(sock, "514:Unknown command.\r\n"); 4371 2 if (++bad_cmd > MAX_BAD) 4372 2 return False; /* too many bad commands */ 4373 2 else 4374 2 return True; 4375 2 } 4376 1 bad_cmd = 0; /* reset bad command count */ 4377 1 return status; 4378 1 } 4379 4380 4381 int quit(char *cmd, int sock) 4382 { 4383 1 writestring(sock, "200:Bye!\r\n"); 4384 1 return False; 4385 1 } 4386 4387 4388 char * get_field(char *ptr, char *field, int lower) 4389 { 4390 1 int ind; 4391 1 4392 1 for (ind= 0; *ptr != '\0' && *ptr != ':'; ptr++, ind++) 4393 1 field[ind] = lower ? _tolower(*ptr) : *ptr; 4394 1 field[ind] = '\0'; 4395 1 if (*ptr == ':') ptr++; /* skip over terminating ":" */ 4396 1 return ptr; 4397 1 } 4398 4399 4400 int read_fields(char *file) 4401 { 4402 1 FILE *cnf; 4403 1 char *ptr, line[256], field[128]; 4404 1 int ind, field_idx, count = 0; 4405 1 4406 1 for (ind = 0; ind < MAX_FIELD; ind++) { 4407 2 fields[ind].number = NULL; 4408 2 fields[ind].name = NULL; 4409 2 fields[ind].desc = NULL; 4410 2 fields[ind].attrib = 0; 4411 2 } 4412 1 4413 1 cnf = fopen(file, "r", "shr=get"); 4414 1 if (cnf == NULL) QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 4 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4415 1 return (False); 4416 1 4417 1 while (fgets(line, sizeof(line), cnf)) { 4418 2 ZapCRLF(line); 4419 2 ptr = line; 4420 2 if ((*ptr == '#') || (*ptr == '\0')) /* comment or blank? */ 4421 2 continue; /* yes, skip line */ 4422 2 count++; 4423 2 ptr = get_field(ptr, field, False); /* field number */ 4424 2 field_idx = atoi(field); 4425 2 fields[field_idx].number = new_string(field); 4426 2 4427 2 ptr = get_field(ptr, field, True); /* field name */ 4428 2 fields[field_idx].name = new_string(field); 4429 2 4430 2 ptr = get_field(ptr, field, False); /* field size (ignore) */ 4431 2 4432 2 ptr = get_field(ptr, field, False); /* field description */ 4433 2 fields[field_idx].desc = new_string(field); 4434 2 4435 2 ptr = get_field(ptr, field, False); /* field option (ignore) */ 4436 2 4437 2 for (;;) { 4438 3 ptr = get_field(ptr, field, True); /* get attribute */ 4439 3 if (strlen(field) == 0) 4440 3 break; /* no more attributes */ 4441 3 fields[field_idx].attrib |= field_attrib(field); 4442 3 } 4443 2 if (fields[field_idx].number < 1) 4444 2 qilog(-1, "Field \"%s\" has illegal field number", 4445 2 fields[field_idx].name); 4446 2 } 4447 1 4448 1 fclose(cnf); 4449 1 return True; 4450 1 } 4451 4452 4453 int write_afield(int field_num, int sock) 4454 { 4455 1 char line[128]; 4456 1 int aidx; 4457 1 4458 1 if (fields[field_num].name == NULL) 4459 1 return False; 4460 1 sprintf(line, "-200:%d:%s:max %d", 4461 1 field_num, fields[field_num].name, DATA_SIZE); 4462 1 for (aidx = 0; aidx < MAX_ATTRIBUTES; aidx++) 4463 1 if (fields[field_num].attrib & attributes[aidx].value) { 4464 2 strcat(line, " "); 4465 2 strcat(line, attributes[aidx].name); 4466 2 } 4467 1 strcat(line, "\r\n"); 4468 1 writestring(sock, line); 4469 1 sprintf(line, "-200:%d:%s:%s\r\n", 4470 1 field_num, fields[field_num].name, fields[field_num].desc); 4471 1 writestring(sock, line); QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 5 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4472 1 return True; 4473 1 } 4474 4475 4476 int fields_cmd(char *cmd, int sock) 4477 { 4478 1 int fidx, aidx, count = 0; 4479 1 char line[256]; 4480 1 Arg *list, *listp; 4481 1 4482 1 list = listp = parse_cmd(cmd, sock); 4483 1 4484 1 if (list == NULL) /* null arg list means all fields */ 4485 1 for (fidx = 0; fidx < MAX_FIELD; fidx++) 4486 1 count += write_afield(fidx, sock); 4487 1 else 4488 1 for (; listp; listp = listp->next) 4489 1 if (listp->field > -1) 4490 1 count += write_afield(listp->field, sock); 4491 1 else 4492 1 writestring(sock, "507:Field does not exist.\r\n"); 4493 1 4494 1 free_args(list); 4495 1 4496 1 writestring(sock, "200:Ok.\r\n"); 4497 1 if (debug) qilog(sock, "Sent %d field definitions", count); 4498 1 return True; 4499 1 } 4500 4501 4502 id_cmd(char *cmd, int sock) 4503 { 4504 1 writestring(sock, "200:Thanks, but we don't use ids here.\r\n"); 4505 1 return True; 4506 1 } 4507 4508 4509 stat_cmd(char *cmd, int sock) 4510 { 4511 1 if ((db_status & 1) == SS$_NORMAL) 4512 1 writestring(sock, "201:Database ready, read-only.\r\n"); 4513 1 else 4514 1 writestring(sock, "475:Database unavailable; try later.\r\n"); 4515 1 return True; 4516 1 } 4517 4518 4519 set_cmd(char *cmd, int sock) 4520 { 4521 1 Arg *list, *listp; 4522 1 4523 1 list = listp = parse_cmd(cmd, sock); 4524 1 for (; listp; listp = listp->next) 4525 1 if (strcmp(listp->name, "debug") == 0) { 4526 2 if (strcmp(listp->value, "on") == 0) { 4527 3 debug = True; 4528 3 writestring(sock, "200:Done - Debug mode on.\r\n"); QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 6 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4529 3 } 4530 2 else if (strcmp(listp->value, "off") == 0) { 4531 3 debug = False; 4532 3 writestring(sock, "200:Done - Debug mode off.\r\n"); 4533 3 } else 4534 2 writestring(sock, "513:Unknown option.\r\n"); 4535 2 } else 4536 1 writestring(sock, "513:Unknown option.\r\n"); 4537 1 free_args(list); 4538 1 return True; 4539 1 } 4540 4541 4542 /* return some arbitrary site info */ 4543 int site_cmd(char *cmd, int sock) 4544 { 4545 1 FILE *fd; 4546 1 char line[128], temp[128]; 4547 1 4548 1 sprintf(temp, "-200:0:version:%s\r\n", VERSION); 4549 1 writestring(sock, temp); 4550 1 if ((fd = fopen(getlogical(SITEINFO_NAME), "r", "shr=get")) == NULL) 4551 1 writestring(sock, "525:No siteinfo available.\r\n"); 4552 1 else { 4553 2 while (fgets(line, sizeof(line), fd)) { 4554 3 ZapCRLF(line); 4555 3 sprintf(temp, "-200:%s\r\n", line); 4556 3 writestring(sock, temp); 4557 3 } 4558 2 writestring(sock, "200:Ok.\r\n"); 4559 2 fclose(fd); 4560 2 } 4561 1 return True; 4562 1 } 4563 4564 4565 /* return the attribute value for the given field name */ 4566 int field_attrib(char *str) 4567 { 4568 1 int ind; 4569 1 4570 1 for (ind = 0; ind < MAX_ATTRIBUTES; ind++) 4571 1 if (*str == _tolower(*attributes[ind].name)) /* check only first char */ 4572 1 return (attributes[ind].value); 4573 1 return (0); /* no match = no bits */ 4574 1 } 4575 4576 4577 /* return the field_number for the given field name */ 4578 int field_number(char *str) 4579 { 4580 1 int ind; 4581 1 4582 1 for (ind = 0; ind < MAX_FIELD; ind++) 4583 1 if (fields[ind].name && (strcmp(str, fields[ind].name) == 0)) 4584 1 return (atoi(fields[ind].number)); 4585 1 return (-1); /* no field number */ QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 7 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4586 1 } 4587 4588 4589 /* get a token as part of the 'field=value' clause */ 4590 /* return pointer to terminator */ 4591 char *get_token(char *cp, char *dp) 4592 { 4593 1 int in_quote = False; 4594 1 4595 1 if (*cp) { 4596 2 while (isspace(*cp)) cp++; /* skip space */ 4597 2 while (*cp && (in_quote || ((*cp != ' ') && (*cp != '=')))) 4598 2 if (*cp == '"') { 4599 3 in_quote = !in_quote; 4600 3 cp++; 4601 3 } 4602 2 else 4603 2 *dp++ = *cp++; 4604 2 } 4605 1 *dp = '\0'; 4606 1 return cp; 4607 1 } 4608 4609 4610 /* cmd = 'verb [field=]value ...' */ 4611 Arg *parse_cmd(char *cmd, int sock) 4612 { 4613 1 int index; 4614 1 char *cp, token[128], temp[128]; 4615 1 Arg *start = NULL, *end = NULL; 4616 1 4617 1 cp = strchr(cmd, ' '); /* skip verb */ 4618 1 while (cp) { 4619 2 cp = get_token(++cp, token); 4620 2 if (strlen(token) == 0) 4621 2 return start; 4622 2 if (start == NULL) 4623 2 start = end = make_arg(NULL, -1, NULL, 0); 4624 2 else { 4625 3 end->next = make_arg(NULL, -1, NULL, 0); 4626 3 end = end->next; 4627 3 } 4628 2 if (*cp == '=') { 4629 3 end->name = new_string(token); 4630 3 end->field = field_number(token); 4631 3 end->type |= TYPE_NAME | TYPE_EQUAL; 4632 3 cp = get_token(++cp, token); 4633 3 } 4634 2 if (strlen(token)) { 4635 3 end->value = new_string(token); 4636 3 end->type |= TYPE_VALUE; 4637 3 } 4638 2 if (strcmp(token, "return") == 0) /* check for special names */ 4639 2 end->type |= TYPE_RETURN; 4640 2 if (end->field == -1) /* if there were no field name given */ 4641 2 end->field = field_number(token); /* try the field value as a field name */ 4642 2 if (debug) { QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 8 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4643 3 sprintf(temp, "-100: Parse >> %s (field %d) = %s\r\n", 4644 3 end->name ? end->name : "", end->field, 4645 3 end->value ? end->value : ""); 4646 3 writestring(sock, temp); 4647 3 } 4648 2 } 4649 1 return start; /* should only get here on null list */ 4650 1 } 4651 4652 4653 Arg *make_arg(char * name, int field, char *value, int type) 4654 { 4655 1 Arg *ptr; 4656 1 4657 1 ptr = malloc(sizeof (Arg)); 4658 1 ptr->type = type; 4659 1 ptr->name = name; 4660 1 ptr->field = field; 4661 1 ptr->value = value; 4662 1 ptr->next = (Arg *) 0; 4663 1 return ptr; 4664 1 } 4665 4666 4667 4668 void free_args(Arg *ptr) 4669 { 4670 1 Arg *next; 4671 1 4672 1 while (ptr) { 4673 2 next = ptr->next; 4674 2 free(ptr); 4675 2 ptr = next; 4676 2 } 4677 1 } 4678 4679 4680 /* copy string into malloc'ed space */ 4681 4682 char *new_string(char *str) 4683 { 4684 1 char *ptr; 4685 1 4686 1 ptr = (char *) malloc(strlen(str) + 1); 4687 1 strcpy(ptr, str); 4688 1 return (ptr); 4689 1 } 4690 4691 4692 void qilog(int sock, char *fmt, ...) 4693 { 4694 1 FILE *logfd; 4695 1 char host_name[256]; 4696 1 time_t Now; 4697 1 char NowBuf[26]; 4698 1 char *cp; 4699 1 char buf[512]; QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 9 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4700 1 va_list arg_ptr; 4701 1 4702 1 va_start(arg_ptr, fmt); 4703 1 vsprintf(buf, fmt, arg_ptr); 4704 1 va_end(arg_ptr); 4705 1 host_name[0] = '\0'; 4706 1 if (sock > -1) 4707 1 inet_netnames(sock, host_name); 4708 1 time(&Now); 4709 1 cp = (char *) ctime(&Now); 4710 1 ZapCRLF(cp); 4711 1 cp = strcpy(NowBuf, cp); 4712 1 if ((logfd = fopen(getlogical(LOG_NAME), "a", 4713 1 "dna=qi.log", "shr=put")) != NULL) { 4714 2 if (strlen(fmt)) { 4715 3 fprintf(logfd, "%s %s : %s\n", cp, host_name, buf); 4716 3 fflush(logfd); 4717 3 } 4718 2 fclose(logfd); 4719 2 } 4720 1 } 4721 4722 4723 void qiabort(int sock, char *str) 4724 { 4725 1 writestring(sock, str); 4726 1 ZapCRLF(str); 4727 1 qilog(sock, "Abort: %s", str); 4728 1 exit(2); 4729 1 } 4730 4731 4732 void *my_realloc(void *mem, int size) 4733 { 4734 1 if ((mem == (void *) 0)) 4735 1 return ((void *) malloc(size)); 4736 1 else 4737 1 return ((void *) realloc(mem, size)); 4738 1 } 4739 4740 4741 /* translate an exec mode logical name */ 4742 char *getlogical(char *name) 4743 { 4744 1 #include psldef 4801 1 #include lnmdef 4856 1 4857 1 typedef struct { 4858 1 short length; 4859 1 short item_code; 4860 1 char *bufadr; 4861 1 short *ret_len_addr; 4862 1 } item_desc; 4863 1 4864 1 struct { 4865 1 item_desc string; 4866 1 int terminator; QI 1-SEP-1993 10:03:52 VAX C V3.2-044 Page 10 V1.0 26-AUG-1993 21:03:20 X$SRC:[CSO]QI.C;2 (1) 4867 1 } trnlst; 4868 1 4869 1 static char result[128]; /* the object returned */ 4870 1 short ret_len = 0; 4871 1 int acmode = PSL$C_EXEC; 4872 1 $DESCRIPTOR(table_dsc, "LNM$SYSTEM_TABLE"); 4873 1 struct dsc$descriptor_s log_dsc = { strlen(name), DSC$K_DTYPE_T, 4874 1 DSC$K_CLASS_S, name }; 4875 1 4876 1 trnlst.string.bufadr = result; 4877 1 trnlst.string.length = sizeof(result); 4878 1 trnlst.string.item_code = LNM$_STRING; 4879 1 trnlst.string.ret_len_addr = &ret_len; 4880 1 trnlst.terminator = 0; 4881 1 4882 1 sys$trnlnm(0, &table_dsc, &log_dsc, &acmode, &trnlst); 4883 1 result[ret_len] = '\0'; 4884 1 return result; 4885 1 } Command Line ------------ CC/DEBUG/NOOP/LIST QI .