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