FIFO existence is used to test for a running kernel.
[egate.git] / kernel / main.c
1 /* Gateway kernel
2  * Europagate, 1995
3  *
4  * $Log: main.c,v $
5  * Revision 1.13  1995/03/28 08:01:25  adam
6  * FIFO existence is used to test for a running kernel.
7  *
8  * Revision 1.12  1995/03/27  12:51:05  adam
9  * New log level in use: GW_LOG_ERRNO.
10  *
11  * Revision 1.11  1995/03/27  08:24:02  adam
12  * First use of gip interface and gw-db.
13  * First work on eti program.
14  *
15  * Revision 1.10  1995/03/01  14:32:25  adam
16  * Better diagnostics. Default is, that only one database selected when
17  * several are known.
18  *
19  * Revision 1.9  1995/02/23  08:32:17  adam
20  * Changed header.
21  *
22  * Revision 1.7  1995/02/22  15:22:33  adam
23  * Much more checking of run-time state. Show command never retrieves
24  * more records than indicated by the previous search request. Help
25  * command available. The maximum number of records retrieved can be
26  * controlled now.
27  *
28  * Revision 1.6  1995/02/22  08:51:34  adam
29  * Output function can be customized in fml, which is used to print
30  * the reply to reply_fd.
31  *
32  * Revision 1.5  1995/02/20  21:16:20  adam
33  * FML support. Bug fixes. Profile for drewdb.
34  *
35  * Revision 1.4  1995/02/17  17:06:16  adam
36  * Minor changes.
37  *
38  * Revision 1.3  1995/02/16  18:35:09  adam
39  * First use of Zdist library. Search requests are supported.
40  * Present requests are not supported yet.
41  *
42  * Revision 1.2  1995/02/16  13:21:00  adam
43  * Organization of resource files for targets and conversion
44  * language implemented.
45  *
46  * Revision 1.1  1995/02/15  17:45:29  adam
47  * First version of email gateway kernel. Email requests are read
48  * from stdin. The output is transferred to an MTA if 'From' is
49  * found in the header - or stdout if absent. No Z39.50 client is used.
50  *
51  */
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <assert.h>
57 #include <unistd.h>
58 #include <sys/types.h>
59 #include <sys/time.h>
60 #include <fcntl.h>
61
62 #include <gip.h>
63 #include "kernel.h"
64
65 FILE *reply_fd = stdout;
66
67 struct gw_kernel_info info;
68
69 static void kernel_events (int userid)
70 {
71     char fifo_client_name[1024];
72     char fifo_server_name[1024];
73     GIP gip;
74     fd_set set_r;
75     int r, gip_fd;
76     struct timeval tv;
77
78     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "kernel event loop");
79
80     sprintf (fifo_client_name, "fifo.c.%d", userid);
81     sprintf (fifo_server_name, "fifo.s.%d", userid);
82
83     gip = gips_initialize (fifo_server_name);
84     gips_open (gip, fifo_client_name);
85     gip_fd = gip_infileno (gip);
86
87     while (1)
88     {
89         FD_ZERO (&set_r);
90         FD_SET (gip_fd, &set_r);
91         tv.tv_sec = 60;
92         tv.tv_usec = 0;
93
94         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "IPC select");
95         r = select (gip_fd+1, &set_r, NULL, NULL, &tv);
96         if (r == -1)
97         {
98             gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, KERNEL_LOG, "select");
99             exit (1);
100         }
101         if (r == 0)
102         {
103             gw_log (GW_LOG_STAT, KERNEL_LOG, "Timeout");
104             break;
105         }
106         if (FD_ISSET (gip_fd, &set_r))
107         {
108             char command[128], *cp;
109
110             if (!(lgets (command, 127, gip_fd)))
111             {
112                 gw_log (GW_LOG_WARN, KERNEL_LOG, "Unexpected close");
113                 break;
114             }
115             if ((cp = strchr (command, '\n')))
116                 *cp = '\0';
117             gw_log (GW_LOG_STAT, KERNEL_LOG, "IPC: %s", command);
118             if (!strcmp (command, "mail"))
119             {
120                 gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Incoming mail...\n");
121                 urp (gip_fd);
122             }
123             else if (!strcmp (command, "stop"))
124             {
125                 gw_log (GW_LOG_DEBUG, KERNEL_LOG, "stop");
126                 break;
127             }
128             else 
129             {
130                 gw_log (GW_LOG_WARN, KERNEL_LOG, "Unknown IPC: %s", command);
131             }
132         }
133     }
134     gips_close (gip);
135     gips_destroy (gip);
136     unlink (fifo_client_name);
137     unlink (fifo_server_name);
138 }
139
140 int main (int argc, char **argv)
141 {
142     int userid = -1;
143
144     info.kernel_res = NULL;
145     info.default_res = "default.res";
146     info.override_res = NULL;
147     *info.target = 0;
148     info.lang = NULL;
149     info.bibset = NULL;
150     info.zass = NULL;
151     info.override_portno = NULL;
152     info.override_hostname = NULL;
153     info.databases = NULL;
154     info.database = NULL;
155 #if USE_FML
156     info.fml = NULL;
157 #endif
158     info.sets = NULL;
159
160     gw_log_init (*argv);
161     info.kernel_res = gw_res_init ();
162     while (--argc > 0)
163     {
164         if (**++argv == '-')
165         {
166             switch (argv[0][1])
167             {
168             case 'H':
169                 fprintf (stderr, "kernel [option..] [resource]\n");
170                 fprintf (stderr, "If no resource file is given");
171                 fprintf (stderr, " default.res is used\n");
172                 fprintf (stderr, "Options:\n");
173                 fprintf (stderr, " -d           Enable debugging log\n");
174                 fprintf (stderr, " -t target    Open target immediately\n");
175                 fprintf (stderr, " -l lang      Set language\n");
176                 fprintf (stderr, " -o resource  Override with resource\n");
177                 fprintf (stderr, " -h host      Override host\n");
178                 fprintf (stderr, " -p port      Override port\n");
179                 fprintf (stderr, " -g log       Set Log file\n");
180                 fprintf (stderr, " -i id        Set IPC userid\n");
181                 exit (1);
182             case 'd':
183                 gw_log_level (GW_LOG_ALL);
184                 break;
185             case 't':
186                 if (argv[0][2])
187                     strcpy (info.target, argv[0]+2);
188                 else if (argc > 0)
189                 {
190                     --argc;
191                     strcpy (info.target, *++argv);
192                 }
193                 else
194                 {
195                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing target name");
196                     exit (1);
197                 }
198                 break;
199             case 'l':
200                 if (argv[0][2])
201                     info.lang = argv[0]+2;
202                 else if (argc > 0)
203                 {
204                     --argc;
205                     info.lang = *++argv;
206                 }
207                 else
208                 {
209                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing language name");
210                     exit (1);
211                 }
212                 break;
213             case 'o':
214                 if (argv[0][2])
215                     info.override_res = argv[0]+2;
216                 else if (argc > 0)
217                 {
218                     --argc;
219                     info.override_res = *++argv;
220                 }
221                 else
222                 {
223                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing override name");
224                     exit (1);
225                 }
226                 break;
227             case 'p':
228                 if (argv[0][2])
229                     info.override_portno = argv[0]+2;
230                 else if (argc > 0)
231                 {
232                     --argc;
233                     info.override_portno = *++argv;
234                 }
235                 else
236                 {
237                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing portno");
238                     exit (1);
239                 }
240                 break;
241             case 'h':
242                 if (argv[0][2])
243                     info.override_hostname = argv[0]+2;
244                 else if (argc > 0)
245                 {
246                     --argc;
247                     info.override_hostname = *++argv;
248                 }
249                 else
250                 {
251                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing hostname");
252                     exit (1);
253                 }
254                 break;
255             case 'g':
256                 if (argv[0][2])
257                     gw_log_file (GW_LOG_ALL, argv[0]+2);
258                 else if (argc > 0)
259                 {
260                     --argc;
261                     gw_log_file (GW_LOG_ALL, *++argv);
262                 }
263                 else
264                 {
265                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing log filename");
266                     exit (1);
267                 }
268                 break;
269             case 'i':
270                 if (argv[0][2])
271                     userid = atoi (argv[0]+2);
272                 else if (argc > 0)
273                 {
274                     --argc;
275                     userid = atoi (*++argv);
276                 }
277                 else
278                 {
279                     gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing user id");
280                     exit (1);
281                 }
282                 break;
283             default:
284                 gw_log (GW_LOG_FATAL, KERNEL_LOG, "unknown option %s", *argv);
285                 exit (1);
286             }
287         }
288         else
289             info.default_res = *argv;
290     }
291     read_kernel_res ();
292     if (userid != -1)
293         kernel_events (userid);
294     else
295         urp (0);
296     return 0;
297 }
298
299 struct gw_user_set *user_set_add (const char *name, int hits)
300 {
301     struct gw_user_set *s;
302
303     s = malloc (sizeof (*s));
304     assert (s);
305
306     s->name = gw_strdup (name);
307     s->hits = hits;
308     s->prev = info.sets;
309     info.sets = s;
310     return s;
311 }
312
313 void user_set_init (void)
314 {
315     struct gw_user_set *s, *s1;
316
317     for (s = info.sets; s; s = s1)
318     {
319         free (s->name);
320         s1 = s->prev;
321         free (s);
322     }
323     info.sets = NULL;
324 }
325
326 struct gw_user_set *user_set_search (const char *name)
327 {
328     struct gw_user_set *s;
329
330     if (!name)
331         return info.sets;
332     for (s = info.sets; s; s = s->prev)
333         if (!strcmp (s->name, name))
334             return s;
335     return NULL;
336 }
337
338 #if USE_FML
339 static void fml_inf_write (int ch)
340 {
341     putc (ch, reply_fd);
342 }
343 static FILE *fml_inf;
344
345 static int fml_inf_read (void)
346 {
347     return getc (fml_inf);
348 }
349 #endif
350
351 void read_kernel_res (void)
352 {
353     char path_prefix[128];
354     char fname[160];
355     const char *v;
356     char *cp;
357     char resource_name[256];
358
359     user_set_init ();
360
361     if (info.bibset)
362         ccl_qual_rm (&info.bibset);
363     info.bibset = ccl_qual_mk ();
364
365     if (info.kernel_res)
366         gw_res_close (info.kernel_res);
367     info.kernel_res = gw_res_init ();
368
369     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, default %s",
370             info.default_res);
371     if (*info.target)
372         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, target %s",
373                 info.target);
374     if (info.lang)
375         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, lang %s",
376                 info.lang);
377
378     if (gw_res_merge (info.kernel_res, info.default_res))
379     {
380         gw_log (GW_LOG_WARN, KERNEL_LOG, "Couldn't read resource file %s",
381                 info.default_res);
382         return;
383     }
384     strcpy (path_prefix, gw_res_get (info.kernel_res, "gw.path", "."));
385     
386     if (*info.target)
387     {
388         sprintf (resource_name, "gw.target.%s", info.target);
389         v = gw_res_get (info.kernel_res, resource_name, NULL);
390         if (v)
391         {
392             sprintf (fname, "%s/%s", path_prefix, v);
393             gw_res_merge (info.kernel_res, fname);
394         }
395     }
396     if (info.lang)
397     {
398         sprintf (resource_name, "gw.lang.%s", info.lang);
399         v = gw_res_get (info.kernel_res, resource_name, NULL);
400         if (v)
401         {
402             sprintf (fname, "%s/%s", path_prefix, v);
403             gw_res_merge (info.kernel_res, fname);
404         }
405     }
406     if (info.override_res)
407     {
408         sprintf (fname, "%s/%s", path_prefix, info.override_res);
409         gw_res_merge (info.kernel_res, fname);        
410     }
411     v = gw_res_get (info.kernel_res, "gw.bibset", NULL);
412     if (v)
413     {
414         FILE *bib_inf;
415
416         sprintf (fname, "%s/%s", path_prefix, v);
417         bib_inf = fopen (fname, "r");
418         if (!bib_inf)
419             gw_log (GW_LOG_WARN, KERNEL_LOG, "cannot open %s", fname);
420         else
421         {
422             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading bib file %s", fname);
423             ccl_qual_file (info.bibset, bib_inf);
424             fclose (bib_inf);
425         }
426     }
427     sprintf (resource_name, "gw.target.%s", info.target);
428     if (*info.target && ! gw_res_get (info.kernel_res, resource_name, NULL))
429     {
430         /* target is there, and there is no sub-resource for it... */
431         char *split;
432
433         if ((split = strchr (info.target, ':')))
434             *split++ = '\0';
435         strncpy (info.hostname, info.target, sizeof(info.hostname)-1);
436         if (split)
437             info.port = atoi (split);
438         else
439             info.port = atoi (gw_res_get
440                               (info.kernel_res, "gw.portno", "210"));
441     }
442     else
443     {
444         strncpy (info.hostname, gw_res_get (info.kernel_res,
445                                             "gw.hostname", "localhost"),
446                  sizeof(info.hostname)-1);
447         info.port = atoi (gw_res_get (info.kernel_res,
448                                       "gw.portno", "210"));
449     }
450     if (info.databases)
451         free (info.databases);
452     if (info.database)
453         free (info.database);
454     v = gw_res_get (info.kernel_res, "gw.databases", "");
455     info.databases = gw_strdup (v);
456     for (cp = info.databases; (cp = strchr (cp, ' ')); cp++)
457         *cp = ',';
458     v = gw_res_get (info.kernel_res, "gw.database", "");
459     if (*v == '\0' && *info.databases)
460     {
461         int len;
462         cp = strchr (info.databases, ',');
463         
464         len = cp ? (cp-info.databases) : strlen (info.databases);
465         info.database = malloc (len+1);
466         assert (info.database);
467         memcpy (info.database, info.databases, len);
468         info.database[len] = '\0';
469     }
470     else
471     {
472         info.database = gw_strdup (v);
473         for (cp = info.database; (cp = strchr (cp, ' ')); cp++)
474             *cp = ',';
475     }
476     if (info.override_portno)
477         info.port = atoi (info.override_portno);
478     if (info.override_hostname)
479         strncpy (info.hostname, info.override_hostname,
480                  sizeof(info.hostname)-1);
481 #if USE_FML
482     if (!info.fml)
483     {
484         v = gw_res_get (info.kernel_res, "gw.fml", "default.fml");    
485         sprintf (fname, "%s/%s", path_prefix, v);
486         fml_inf = fopen (fname, "r");
487         if (!fml_inf)
488             gw_log (GW_LOG_WARN, KERNEL_LOG,
489                     "cannot open fml script %s", fname);
490         else
491         {
492             info.fml = fml_open ();
493             info.fml->read_func = fml_inf_read;
494             info.fml->write_func = fml_inf_write;
495             fml_preprocess (info.fml);
496             fml_exec (info.fml);
497             fclose (fml_inf);
498         }
499     }
500 #endif
501 }