/* 
 * dbskkd-cdb.c
 * ucspi-tcp-style SKK Server for D. J. Bernstein's cdb
 * $Id: dbskkd-cdb.c,v 3.5 2000/04/28 13:06:02 kenji Exp $
 * (cdb, daemontools and ucspi-tcp required)
 *
 * Copyright (c) 1998-2000 by Kenji Rikitake. All rights reserved.
 * See LICENSE of the distribution kit for the redistribution conditions.
 */

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "cdb.h"

/* 
 * dbskkd chroot()'ed directory
 */
#ifndef SERVER_DIR
#define SERVER_DIR	"/service/dbskkd-cdb/root"
#endif /* SERVER_DIR */

/* 
 * dbskkd dictionary file 
 * NOTE: specify chroot()'ed path here
 */
#ifndef JISHO_FILE
#define JISHO_FILE	"/SKK-JISYO.L.cdb"
#endif /* JISHO_FILE */

#define	BUFSIZE		(1024)	/* max size of a request */
#define DATASIZE	(2048)	/* max size of a result */

#define CLIENT_END	'0'
#define CLIENT_REQUEST	'1'
#define CLIENT_VERSION	'2'
#define CLIENT_HOST	'3'

#define SERVER_FOUND	'1'
#define SERVER_NOT_FOUND '4'

#define STDIN (fileno(stdin))
#define STDOUT (fileno(stdout))

/* must be terminated with space */
#define VERSION "dbskkd-cdb-1.71dev " 

/* diesys() originally from DJB's cdb-0.55, modified */
void diesys(char *why)
{ 
  fprintf(stderr, "dbskkd-cdb: pid %d ", getpid());
  perror(why); 
  exit(1); 
}

/*
 * main program
 */

int main(int argc, char *argv[])
{
  static unsigned char combuf[BUFSIZE];
  static char data[DATASIZE];
  register unsigned char *pbuf, *key, *p;
  static struct cdb diccdb;
  int id, dicfd, ex, length;
  unsigned int keylen, datalen;

  /* chroot to server directory */
  if (chdir(SERVER_DIR) == -1)
    diesys("cannot chdir() to " SERVER_DIR);
  if (chroot(".") == -1)
    diesys("cannot chroot()");
  /* set uid and gid */
  p = getenv("GID");
  if (p) {
    id = atoi(p);
    if (setgroups(1, (gid_t *)&id) == -1)
      diesys("cannot setgroups()");
    if (setgid(id) == -1)
      diesys("cannot setgid()");
    }
  p = getenv("UID");
  if (p) {
    id = atoi(p);
    if (setuid(id) == -1)
      diesys("cannot setuid()");
    }

  /* open dictionary cdb file */
  if ((dicfd = open(JISHO_FILE, O_RDONLY, S_IRUSR)) < 0) {
    diesys("cannot open() the dictionary file " JISHO_FILE);
    /* NOTREACHED */
  }
  cdb_init(&diccdb, dicfd);

  /* command loop */
  ex = 0;
  while (!ex) {
    length = read(STDIN, &combuf[0], BUFSIZE - 1);
    if (length < 0)
      diesys("read error from stdin");
    else if (length == 0) {
      fprintf(stderr, "dbskkd-cdb: pid %d end of file detected\n", getpid());
      ex = 1;
      break;
    }
    switch (combuf[0]) {
    case CLIENT_END:
      fprintf(stderr, 
	      "dbskkd-cdb: pid %d end of conversion requested\n", getpid());
      ex = 1;
      break;
    case CLIENT_VERSION:
      if (write(STDOUT, VERSION, sizeof(VERSION) - 1) < 0)
        diesys("write error (version string)"); 
      break;
    case CLIENT_HOST:
      /* use tcp-environ */
      p = getenv("TCPLOCALHOST");
      if (p) {
        if (write(STDOUT, p, strlen(p)) < 0)
          diesys("write error (TCPLOCALHOST)"); 
	}
      else {
	if (write(STDOUT, "UNKNOWN", 7) < 0)
	  diesys("write error (UNKNOWN TCPLOCALHOST)");
	}
      if (write(STDOUT, ":", 1) < 0)
	diesys("write error (colon after TCPLOCALHOST)");
      p = getenv("TCPLOCALIP");
      if (p) {
        if (write(STDOUT, p, strlen(p)) < 0)
          diesys("write error (TCPLOCALIP)"); 
	}
      else {
	if (write(STDOUT, "UNKNOWNIP", 7) < 0)
	  diesys("write error (UNKNOWN TCPLOCALIP)");
	}
      if (write(STDOUT, ": ", 2) < 0)
	diesys("write error (colon and space after TCPLOCALIP)");
      break;
    case CLIENT_REQUEST:
      /* get size of key */
      key = &combuf[1];
      for (pbuf = &combuf[1];
           *pbuf != ' ' && pbuf != &combuf[length - 1];
           pbuf++) {}
      keylen = pbuf - &combuf[1];
      if (keylen <= 0)
        diesys("invalid keysize");
      switch (cdb_find(&diccdb, key, keylen)) {
      case -1:
        diesys("fatal error on cdb_find()");
      case 1: /* found */
        if ((datalen = cdb_datalen(&diccdb)) >= DATASIZE - 2)
  	  diesys("searched entry too long");
	/* generate the answer string */
	p = data;
	*p++ = SERVER_FOUND;
        if (cdb_read(&diccdb, p, datalen, cdb_datapos(&diccdb)) < 0)
  	  diesys("read error (seeked dictionary data)");
        p += datalen;
        *p = '\n';
        /* sending found code and the result data string with LF */
        if (write(STDOUT, data, datalen + 2) < 0)
  	  diesys("write error (converted data)");
        break;
      case 0: /* NOT found */
        /* generate the answer string */
        combuf[0] = SERVER_NOT_FOUND;
        *pbuf = '\n';
        /* sending error code and the key string with LF */
        /* this action is required by skkinput */
        if (write(STDOUT, combuf, keylen + 2) < 0)
  	  diesys("write error (NOT_FOUND message)");
        break;
      default: /* unknown value */ 
        diesys("unknown return value from cdb_seek()");
      }
      break;
    default:
      fprintf(stderr, 
	      "dbskkd-cdb: pid %d unknown client request code = %d\n",
	       getpid(), combuf[0]);
      exit(1);
    }
  }

  /* close dictionary db file */
  cdb_free(&diccdb);
  if (close(dicfd) != 0)
    diesys("cannot close() the dictionary file");

  exit(0);
}

/* end of program */


syntax highlighted by Code2HTML, v. 0.9.1