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