1 /*
2  * dbskkd.c
3  * inetd-style SKK Server for Berkeley-DBnized dictionary file
4  * Version dbskkd-0.2beta
5  * based on SKK Version 3.9.3
6  * Copyright (c) 1996 by Kenji Rikitake <kenji@reseau.toyonaka.osaka.jp>
7  * Original copyright notice at the end of this source file
8  * $Id: dbskkd.c,v 1.9 1996/11/09 12:16:39 kenji Exp $
9  */
10 
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <netdb.h>
22 #include <signal.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <syslog.h>
26 #include <db.h>
27 
28 /* dbskkd working directory */
29 #ifndef SERVER_DIR
30 #define	SERVER_DIR	"/usr/local/etc/dbskkd/"
31 #endif /* SERVER_DIR */
32 
33 /* dbskkd dictionary file (path relative to SERVER_DIR) */
34 #ifndef JISHO_FILE
35 #define JISHO_FILE	"./SKK-JISYO.L.db"
36 #endif /* JISHO_FILE */
37 
38 #define	BUFSIZE		1024	/* max size of a request */
39 
40 #define CLIENT_END	'0'
41 #define CLIENT_REQUEST	'1'
42 #define CLIENT_VERSION	'2'
43 #define CLIENT_HOST	'3'
44 
45 #define SERVER_ERROR	"0"
46 #define SERVER_FOUND	"1"
47 #define SERVER_NOT_FOUND "4"
48 
49 #define STDIN	(fileno(stdin))
50 #define STDOUT	(fileno(stdout))
51 
52 void err __P((const char *, ...));
53 void setproctitle __P((const char *, ...));
54 
55 char	pgmver[] = "dbskkd-0.2 ";	/* version number */
56 
57 char	hname[BUFSIZ];	/* hostname and IP address */
58 DB	*jisho_dbp;	/* DB structure for the shared dictionary */
59 HASHINFO jisho_hash;	/* HASHINFO for the shared dictionary */
60 
61 /*
62  * main server loop:
63  * DB-style hashed database search
64  */
65 
search()66 int search()
67 {
68   unsigned char	combuf[BUFSIZE];
69   register unsigned char *pbuf;
70   int length, errcode, get_status;
71   DBT key, data;
72 
73   if ((length = read(STDIN, &combuf[0], BUFSIZE)) <= 0) {
74     err("read error from stdin: %s", strerror(errno));
75     /* NOTREACHED */
76   }
77 
78   switch (combuf[0]) {
79 
80   case CLIENT_END:
81     syslog(LOG_NOTICE, "end of conversion requested");
82     return -1;
83     /* NOTREACHED */
84     break; /* foolproof */
85 
86   case CLIENT_VERSION:
87     if (write(STDOUT, pgmver, strlen(pgmver)) < 0) {
88       err("write error (version string): %s",
89 	  strerror(errno));
90       /* NOTREACHED */
91     }
92     return 0;
93     /* NOTREACHED */
94     break; /* foolproof */
95 
96   case CLIENT_HOST:
97     if (write(STDOUT, hname, strlen(hname)) < 0) {
98       err("write error (host info): %s", strerror(errno));
99       /* NOTREACHED */
100     }
101     return 0;
102     /* NOTREACHED */
103     break; /* foolproof */
104 
105   case CLIENT_REQUEST:
106     /* get size of key */
107     key.data = &combuf[1];
108     for (pbuf = &combuf[1];
109          *pbuf != ' ' && pbuf != &combuf[length - 1];
110          pbuf++) {}
111     key.size = pbuf - &combuf[1];
112 
113     if (key.size <= 0) {
114       err("invalid keysize = %d", key.size);
115       /* NOTREACHED */
116     }
117     else {
118       get_status = jisho_dbp->get(jisho_dbp, &key, &data, 0);
119     }
120     switch (get_status) {
121     case -1:
122       err("fatal error on DB get routine: %s", strerror(errno));
123       /* NOTREACHED */
124       break; /* foolproof */
125     case 0: /* found */
126       /* sending found code and the result data string with LF */
127       if ((errcode = write(STDOUT, SERVER_FOUND, 1)) >= 0) {
128         if ((errcode = write(STDOUT, data.data, data.size)) >= 0) {
129 	  errcode = write(STDOUT, "\n", 1);
130           if (errcode < 0) {
131 	    err("write error (converted data): %s",
132 		 strerror(errno));
133 	    /* NOTREACHED */
134           }
135           return 0;
136           /* NOTREACHED */
137         }
138       }
139       break;
140     case 1: /* NOT found */
141       /* sending error code and the key string with LF */
142       /* this action is required by skkinput */
143       if ((errcode = write(STDOUT, SERVER_NOT_FOUND, 1)) >= 0) {
144         if ((errcode = write(STDOUT, key.data, key.size)) >= 0) {
145 	  errcode = write(STDOUT, "\n", 1);
146           if (errcode < 0) {
147 	    err("write error (NOT_FOUND message): %s",
148 		 strerror(errno));
149 	    /* NOTREACHED */
150           }
151           return 0;
152           /* NOTREACHED */
153         }
154       }
155       return 0;
156       /* NOTREACHED */
157       break; /* foolproof */
158     default: /* unknown value */
159       err("unknown return value %d from DB get routine", get_status);
160       /* NOTREACHED */
161       break; /* foolproof */
162     }
163     break;
164   default:
165     err("unknown client request code %d", combuf[0]);
166     /* NOTREACHED */
167     break; /* foolproof */
168   }
169   /* NOTREACHED */
170 }
171 
172 /*
173  * main program
174  */
175 
main(argc,argv)176 int main(argc, argv)
177 int argc;
178 char *argv[];
179 {
180   struct hostent *hp;
181   char **p, *lp;
182   struct in_addr addr;
183   struct sockaddr_in sin;
184   int sval;
185 
186   /* open syslog */
187   openlog("dbskkd", LOG_PID | LOG_CONS, LOG_DAEMON);
188 
189   /* chdir to server directory */
190   if (chdir(SERVER_DIR) != 0) {
191     err("cannot chdir() to %s: %s", SERVER_DIR, strerror(errno));
192     }
193   /* set umask to g-w, o-rwx */
194   (void)umask(027);
195 
196   /* open dictionary db file */
197   if ((jisho_dbp = dbopen(JISHO_FILE, O_RDONLY, S_IRUSR, DB_HASH, &jisho_hash)) == NULL) {
198     err("cannot dbopen() the dictionary file %s: %s", JISHO_FILE,
199 	 strerror(errno));
200     /* NOTREACHED */
201   }
202 
203   /* get host info */
204   if (gethostname(hname, BUFSIZE) < 0) {
205     err("gethostname: %s", strerror(errno));
206     /* NOTREACHED */
207   }
208   hp = gethostbyname(hname);
209   p = hp->h_addr_list;
210   while (*p != NULL) {
211     strcat(hname, ":");
212     memcpy(&addr.s_addr, *p, hp->h_length);
213     strcat(hname, inet_ntoa(addr));
214     p++;
215   }
216   strcat(hname, ": ");
217 
218   /* get peer info */
219   sval = sizeof(sin);
220   if (getpeername(0, (struct sockaddr *)&sin, &sval) < 0) {
221     err("getpeername: %s", strerror(errno));
222     /* NOTREACHED */
223     }
224   if (hp = gethostbyaddr((char *)&sin.sin_addr.s_addr,
225       sizeof(sin.sin_addr.s_addr), AF_INET))
226     lp = hp->h_name;
227   else
228     lp = inet_ntoa(sin.sin_addr);
229 
230 #ifdef LOG_PEERINFO
231   /* log peer info */
232   syslog(LOG_NOTICE, "connected from %s", lp);
233 #endif /* LOG_PEERINFO */
234   /* set process status string */
235   setproctitle("serving %s", lp);
236 
237   /* command loop */
238   while(search() == 0) {}
239 
240   /* close dictionary db file */
241   if (jisho_dbp->close(jisho_dbp))
242     err("cannot dbp->close() the dictionary file: %s", strerror(errno));
243     /* NOTREACHED */
244 
245   exit(0);
246 }
247 
248 /*
249  * the function err() for syslog retains
250  * the following copyright conditions
251  */
252 /*
253  * Copyright (c) 1983, 1993
254  *      The Regents of the University of California.  All rights reserved.
255  *
256  * Redistribution and use in source and binary forms, with or without
257  * modification, are permitted provided that the following conditions
258  * are met:
259  * 1. Redistributions of source code must retain the above copyright
260  *    notice, this list of conditions and the following disclaimer.
261  * 2. Redistributions in binary form must reproduce the above copyright
262  *    notice, this list of conditions and the following disclaimer in the
263  *    documentation and/or other materials provided with the distribution.
264  * 3. All advertising materials mentioning features or use of this software
265  *    must display the following acknowledgement:
266  *      This product includes software developed by the University of
267  *      California, Berkeley and its contributors.
268  * 4. Neither the name of the University nor the names of its contributors
269  *    may be used to endorse or promote products derived from this software
270  *    without specific prior written permission.
271  *
272  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
273  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
274  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
275  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
276  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
277  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
278  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
280  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
282  * SUCH DAMAGE.
283  */
284 
285 #if __STDC__
286 #include <stdarg.h>
287 #else
288 #include <varargs.h>
289 #endif
290 
291 void
292 #if __STDC__
err(const char * fmt,...)293 err(const char *fmt, ...)
294 #else
295 err(fmt, va_alist)
296         char *fmt;
297         va_dcl
298 #endif
299 {
300         va_list ap;
301 #if __STDC__
302         va_start(ap, fmt);
303 #else
304         va_start(ap);
305 #endif
306         (void)vsyslog(LOG_ERR, fmt, ap);
307         va_end(ap);
308         exit(1);
309         /* NOTREACHED */
310 }
311 
312 /* end of program */
313 
314 /* original skkserv comment follows */
315 
316 /* skkserv.c
317  * SKK Server Version 3.9.3 of Jun 17, 1994
318  * Copyright (C) 1994 Yukiyoshi Kameyama (kam@riec.tohoku.ac.jp)
319  *
320  * Programmed by
321  * Yukiyoshi Kameyama (kam@riec.tohoku.ac.jp)
322  * Research Institute of Electrical Communication
323  * Tohoku University
324  *
325  * Contributed by
326  * Nobu Takahashi (nt@hpycla.yhp.co.jp) for System V patch
327  * Chikahiro Kimura (kimura@2oa.kb.nec.co.jp) for "ntohs" bug
328  * Koji Kawaguchi (guchi@pfu.fujitsu.co.jp) for various improvement
329  * Hironobu Takahashi (takahasi@tiny.or.jp) for patch for char/int typing
330  * Kazushi Marukawa (kazushi@kubota.co.jp) for cleaning up behavior in PRIVATE mode
331  * TSUMURA Kazumasa (tsumura@fml.ec.tmit.ac.jp) for pointing out a bug in okuri-ari/nasi test
332  *
333  * This program is free software; you can redistribute it and/or modify
334  * it under the terms of the GNU General Public License as published by
335  * the Free Software Foundation; either versions 2, or (at your option)
336  * any later version.
337  *
338  * This program is distributed in the hope that it will be useful
339  * but WITHOUT ANY WARRANTY; without even the implied warranty of
340  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
341  * GNU General Public License for more details.
342  *
343  * You should have received a copy of the GNU General Public License
344  * along with SKK, see the file COPYING.  If not, write to the Free
345  * Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
346  */
347 /*
348  * Description
349  *	"skkserv" is a server daemon for an SKK/Nemacs client, which
350  *	provides a facility of fast looking-up of an SKK-dictionary.
351  *	skkserv and an SKK/Nemacs client can run on different hosts
352  *	which are connected by a TCP/IP network.
353  *
354  *	An old-style SKK-dictionary is a sorted sequence of lines in
355  *	the form:
356  *		YOMI /TANGO1/TANGO2/.../TANGOn/
357  *	A new-style SKK-dictionary consists of two parts:
358  *	The first part begins with the line
359  *		;; okuri-ari entries.
360  *	followed by the reverse-sorted sequence of lines in the same
361  *	form as old-style.  In the first part, all the YOMI entries
362  *	have "okurigana".
363  *	The second part begins with the line
364  *		;; okuri-nasi entries.
365  *	followed by the sorted sequence of lines in the same form as
366  *	old-style.  In the second part, all the YOMI entries do NOT
367  *	have "okurigana".
368  *	Other lines whose first two characters are ";;" will be ignored.
369  *
370  *	NOTE: the "sort" and "reverse-sort" should be emacs-sort, not
371  *	UNIX sort (unsigned char, shorter is earlier).
372  *
373  *	Once invoked with a dictionary, the server runs permanently,
374  *	and waits for client's requests.
375  *	A client, usually invoked by SKK/Nemacs, requests the server
376  *	to transform a string (YOMI) to another string(/TANGO1/.../).
377  *	Communication between the server and a client is done through
378  *	a TCP-port "skkserv" by a UNIX socket.
379  *	The server looks up the dictionary with the input string
380  *	as the key, and replies its value to the client.
381  *	If the input string is not found in the dictionary it replies
382  *	'Not Found'.
383  */
384 
385 /*
386  * Client Request Form
387  *   "0"	end of connection
388  *   "1eee "	eee is keyword in EUC code with ' ' at the end
389  *   "2"	skkserv version number
390  *   "3"	hostname and its IP addresses
391  *
392  * Server Reply Form for "1eee"
393  *   "0"	Error
394  *   "1eee"	eee is the associated line separated by '/'
395  *   "4"	Not Found
396  *
397  * Server Reply Form for "2"
398  *   "A.B "	A for major version number, B for minor version number
399  *		followed by a space
400  *
401  * Server Reply Form for "3"
402  *   "string:addr1:...: "  string for hostname, addr1 for an IP address
403  *	           	followed by a space
404  *			addrs should be in dotted quad form
405  */
406 
407 /* end of source file */
408