-/* Gateway kernel
+/*
+ * Copyright (c) 1995, the EUROPAGATE consortium (see below).
+ *
+ * The EUROPAGATE consortium members are:
+ *
+ * University College Dublin
+ * Danmarks Teknologiske Videnscenter
+ * An Chomhairle Leabharlanna
+ * Consejo Superior de Investigaciones Cientificas
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation, in whole or in part, for any purpose, is hereby granted,
+ * provided that:
+ *
+ * 1. This copyright and permission notice appear in all copies of the
+ * software and its documentation. Notices of copyright or attribution
+ * which appear at the beginning of any file must remain unchanged.
+ *
+ * 2. The names of EUROPAGATE or the project partners may not be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * 3. Users of this software (implementors and gateway operators) agree to
+ * inform the EUROPAGATE consortium of their use of the software. This
+ * information will be used to evaluate the EUROPAGATE project and the
+ * software, and to plan further developments. The consortium may use
+ * the information in later publications.
+ *
+ * 4. Users of this software agree to make their best efforts, when
+ * documenting their use of the software, to acknowledge the EUROPAGATE
+ * consortium, and the role played by the software in their work.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
+ * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/* Gateway kernel - Main
* Europagate, 1995
*
* $Log: main.c,v $
- * Revision 1.2 1995/02/16 13:21:00 adam
+ * Revision 1.25 1995/05/16 09:40:42 adam
+ * LICENSE. Setting of CCL token names (and/or/not/set) in read_kernel_res.
+ *
+ * Revision 1.24 1995/05/04 10:40:07 adam
+ * More work on Def-settings.
+ *
+ * Revision 1.23 1995/05/03 16:34:18 adam
+ * CCL def command, i.e. user definitions - saved as resource files.
+ *
+ * Revision 1.22 1995/05/03 07:37:39 adam
+ * CCL commands stop/continue implemented. New functions gw_res_{int,bool}
+ * are used when possible.
+ *
+ * Revision 1.21 1995/05/01 16:26:56 adam
+ * More work on resource monitor.
+ *
+ * Revision 1.20 1995/05/01 12:43:32 adam
+ * First work on resource monitor program.
+ *
+ * Revision 1.19 1995/04/19 16:01:58 adam
+ * Some hacks to get the FIFO communication work!! Isn't reliable.
+ * Resource gw.account added - default account info.
+ *
+ * Revision 1.18 1995/04/19 13:19:09 adam
+ * New command: account - for authentication.
+ *
+ * Revision 1.17 1995/04/19 10:46:18 adam
+ * Persistency works much better now. New command: status - history-like
+ *
+ * Revision 1.16 1995/04/19 07:31:07 adam
+ * First work on Z39.50 persistence.
+ *
+ * Revision 1.15 1995/04/17 09:34:30 adam
+ * Timeout (idletime) adjustable. Minor changes in kernel.
+ *
+ * Revision 1.14 1995/03/28 11:42:34 adam
+ * First use of string-queue utility.
+ *
+ * Revision 1.13 1995/03/28 08:01:25 adam
+ * FIFO existence is used to test for a running kernel.
+ *
+ * Revision 1.12 1995/03/27 12:51:05 adam
+ * New log level in use: GW_LOG_ERRNO.
+ *
+ * Revision 1.11 1995/03/27 08:24:02 adam
+ * First use of gip interface and gw-db.
+ * First work on eti program.
+ *
+ * Revision 1.10 1995/03/01 14:32:25 adam
+ * Better diagnostics. Default is, that only one database selected when
+ * several are known.
+ *
+ * Revision 1.9 1995/02/23 08:32:17 adam
+ * Changed header.
+ *
+ * Revision 1.7 1995/02/22 15:22:33 adam
+ * Much more checking of run-time state. Show command never retrieves
+ * more records than indicated by the previous search request. Help
+ * command available. The maximum number of records retrieved can be
+ * controlled now.
+ *
+ * Revision 1.6 1995/02/22 08:51:34 adam
+ * Output function can be customized in fml, which is used to print
+ * the reply to reply_fd.
+ *
+ * Revision 1.5 1995/02/20 21:16:20 adam
+ * FML support. Bug fixes. Profile for drewdb.
+ *
+ * Revision 1.4 1995/02/17 17:06:16 adam
+ * Minor changes.
+ *
+ * Revision 1.3 1995/02/16 18:35:09 adam
+ * First use of Zdist library. Search requests are supported.
+ * Present requests are not supported yet.
+ *
+ * Revision 1.2 1995/02/16 13:21:00 adam
* Organization of resource files for targets and conversion
* language implemented.
*
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <gip.h>
+#include <strqueue.h>
#include "kernel.h"
-GwRes kernel_res = NULL;
-const char *default_res = "default.res";
-const char *target = NULL;
-const char *lang = NULL;
-CCL_bibset bibset = NULL;
-
FILE *reply_fd = stdout;
+struct gw_kernel_info info;
+
+static void kernel_events (struct str_queue *queue)
+{
+ char fifo_client_name[1024];
+ char fifo_server_name[1024];
+ char line_buf[1024];
+ GIP gip;
+ fd_set set_r;
+ int r, gip_fd;
+ struct timeval tv;
+ int timeout;
+ int continuation = 0;
+ int extra_fd;
+ int persist_flag;
+
+ persist_flag = gw_res_bool (info.kernel_res, "gw.persist", 0);
+ timeout = gw_res_int (info.kernel_res, "gw.timeout", 600);
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "event loop");
+
+ sprintf (fifo_client_name, "fifo.c.%d", info.userid);
+ sprintf (fifo_server_name, "fifo.s.%d", info.userid);
+
+ gip = gips_initialize (fifo_server_name);
+ gips_open (gip, fifo_client_name);
+ gip_fd = gip_infileno (gip);
+ extra_fd = open (fifo_server_name, O_WRONLY);
+
+ while (1)
+ {
+ FD_ZERO (&set_r);
+ FD_SET (gip_fd, &set_r);
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "IPC select");
+ r = select (gip_fd+1, &set_r, NULL, NULL, &tv);
+ if (r == -1)
+ {
+ gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, KERNEL_LOG, "select");
+ exit (1);
+ }
+ if (r == 0)
+ {
+ gw_log (GW_LOG_STAT, KERNEL_LOG, "Timeout after %d seconds",
+ timeout);
+ if (info.zass && persist_flag)
+ save_p_state (info.userid);
+ break;
+ }
+ if (FD_ISSET (gip_fd, &set_r))
+ {
+ char command[128], *cp;
+
+ if (!(lgets (command, 127, gip_fd)))
+ {
+ gw_log (GW_LOG_WARN, KERNEL_LOG, "Unexpected close");
+ break;
+ }
+ if ((cp = strchr (command, '\n')))
+ *cp = '\0';
+ gw_log (GW_LOG_STAT, KERNEL_LOG, "IPC: %s", command);
+ if (!strcmp (command, "mail"))
+ {
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Incoming mail");
+ while (lgets (line_buf, sizeof(line_buf)-1, gip_fd))
+ str_queue_enq (queue, line_buf);
+ urp_start (continuation, queue);
+ if (persist_flag && !continuation)
+ load_p_state (info.userid);
+ r = urp_command (queue);
+ if (r == 1) /* stop? */
+ {
+ info.zass = NULL; /* delete association */
+ *info.target = 0; /* indicate no target */
+ read_kernel_res(); /* reread resources */
+ if (persist_flag)
+ del_p_state (info.userid); /* remove persist file */
+ }
+ urp_end ();
+ while (str_queue_deq (queue, 0, 0))
+ ;
+ }
+ else if (!strcmp (command, "stop"))
+ {
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "stop");
+ break;
+ }
+ else
+ {
+ gw_log (GW_LOG_WARN, KERNEL_LOG, "Unknown IPC: %s", command);
+ }
+ continuation = 1;
+ }
+ }
+ close (extra_fd);
+ gips_close (gip);
+ gips_destroy (gip);
+
+ unlink (fifo_client_name);
+ unlink (fifo_server_name);
+}
+
int main (int argc, char **argv)
{
+ struct str_queue *queue;
+
+ info.kernel_res = NULL;
+ info.default_res = "default.res";
+ info.override_res = NULL;
+ *info.target = 0;
+ *info.account = 0;
+ info.lang = NULL;
+ info.bibset = NULL;
+ info.zass = NULL;
+ info.override_portno = NULL;
+ info.override_hostname = NULL;
+ info.databases = NULL;
+ info.database = NULL;
+ info.setno = -1;
+ info.userid = -1;
+#if USE_FML
+ info.fml = NULL;
+#endif
+ info.sets = NULL;
+
gw_log_init (*argv);
- kernel_res = gw_res_init ();
+ info.kernel_res = gw_res_init ();
while (--argc > 0)
{
if (**++argv == '-')
{
switch (argv[0][1])
{
+ case 'H':
+ fprintf (stderr, "kernel [option..] [resource]\n");
+ fprintf (stderr, "If no resource file is given");
+ fprintf (stderr, " default.res is used\n");
+ fprintf (stderr, "Options:\n");
+ fprintf (stderr, " -d Enable debugging log\n");
+ fprintf (stderr, " -t target Open target immediately\n");
+ fprintf (stderr, " -g lang Set language\n");
+ fprintf (stderr, " -o resource Override with resource\n");
+ fprintf (stderr, " -h host Override host\n");
+ fprintf (stderr, " -p port Override port\n");
+ fprintf (stderr, " -l log Set Log file\n");
+ fprintf (stderr, " -i id Set IPC userid\n");
+ exit (1);
case 'd':
+ gw_log_level (GW_LOG_ALL & ~RES_DEBUG);
+ break;
+ case 'D':
gw_log_level (GW_LOG_ALL);
break;
case 't':
if (argv[0][2])
- target = argv[0]+2;
+ strcpy (info.target, argv[0]+2);
+ else if (argc > 0)
+ {
+ --argc;
+ strcpy (info.target, *++argv);
+ }
+ else
+ {
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing target name");
+ exit (1);
+ }
+ break;
+ case 'g':
+ if (argv[0][2])
+ info.lang = argv[0]+2;
+ else if (argc > 0)
+ {
+ --argc;
+ info.lang = *++argv;
+ }
+ else
+ {
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing language name");
+ exit (1);
+ }
+ break;
+ case 'o':
+ if (argv[0][2])
+ info.override_res = argv[0]+2;
+ else if (argc > 0)
+ {
+ --argc;
+ info.override_res = *++argv;
+ }
+ else
+ {
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing override name");
+ exit (1);
+ }
+ break;
+ case 'p':
+ if (argv[0][2])
+ info.override_portno = argv[0]+2;
else if (argc > 0)
{
--argc;
- target= *++argv;
+ info.override_portno = *++argv;
}
else
{
- gw_log (GW_LOG_FATAL, "main", "missing target name");
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing portno");
+ exit (1);
+ }
+ break;
+ case 'h':
+ if (argv[0][2])
+ info.override_hostname = argv[0]+2;
+ else if (argc > 0)
+ {
+ --argc;
+ info.override_hostname = *++argv;
+ }
+ else
+ {
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing hostname");
exit (1);
}
break;
case 'l':
if (argv[0][2])
- lang = argv[0]+2;
+ gw_log_file (GW_LOG_ALL, argv[0]+2);
else if (argc > 0)
{
--argc;
- lang = *++argv;
+ gw_log_file (GW_LOG_ALL, *++argv);
}
else
{
- gw_log (GW_LOG_FATAL, "main", "missing language name");
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing log filename");
exit (1);
}
break;
+ case 'i':
+ if (argv[0][2])
+ info.userid = atoi (argv[0]+2);
+ else if (argc > 0)
+ {
+ --argc;
+ info.userid = atoi (*++argv);
+ }
+ else
+ {
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "missing user id");
+ exit (1);
+ }
+ break;
default:
- gw_log (GW_LOG_FATAL, "main", "unknown option %s", *argv);
+ gw_log (GW_LOG_FATAL, KERNEL_LOG, "unknown option %s", *argv);
exit (1);
}
}
else
- default_res = *argv;
+ info.default_res = *argv;
+ }
+ if (!(queue = str_queue_mk ()))
+ {
+ gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, KERNEL_LOG, "str_queue_mk");
+ exit (1);
+ }
+ if (info.userid != -1)
+ {
+ read_kernel_res ();
+ kernel_events (queue);
+ }
+ else
+ {
+ char line_buf[512];
+ read_kernel_res ();
+ while (lgets (line_buf, sizeof(line_buf)-1, 0))
+ str_queue_enq (queue, line_buf);
+ urp_start (0, queue);
+ urp_command (queue);
+ urp_end ();
}
- read_kernel_res ();
- urp (stdin);
return 0;
}
+struct gw_user_set *user_set_add (const char *name, int hits,
+ const char *database,
+ struct ccl_rpn_node *rpn,
+ int present_flag,
+ const char *search_str)
+{
+ struct gw_user_set *s;
+
+ s = malloc (sizeof (*s));
+ assert (s);
+
+ s->name = gw_strdup (name);
+ s->hits = hits;
+ s->database = gw_strdup (database);
+ s->rpn = rpn;
+ s->present_flag = present_flag;
+ s->search_str = gw_strdup (search_str);
+ s->prev = info.sets;
+ info.sets = s;
+ return s;
+}
+
+void user_set_init (void)
+{
+ struct gw_user_set *s, *s1;
+
+ for (s = info.sets; s; s = s1)
+ {
+ free (s->name);
+ free (s->database);
+ ccl_rpn_delete (s->rpn);
+ s1 = s->prev;
+ free (s);
+ }
+ info.sets = NULL;
+}
+
+struct gw_user_set *user_set_search (const char *name)
+{
+ struct gw_user_set *s;
+
+ if (!name)
+ return info.sets;
+ for (s = info.sets; s; s = s->prev)
+ if (!strcmp (s->name, name))
+ return s;
+ return NULL;
+}
+
+#if USE_FML
+static void fml_inf_write (int ch)
+{
+ putc (ch, reply_fd);
+}
+static FILE *fml_inf;
+
+static int fml_inf_read (void)
+{
+ return getc (fml_inf);
+}
+#endif
+
void read_kernel_res (void)
{
char path_prefix[128];
char fname[160];
const char *v;
+ char *cp;
char resource_name[256];
- bibset = ccl_qual_mk ();
-
- gw_log (GW_LOG_DEBUG, "main", "reading kernel resource, default %s",
- default_res);
- if (target)
- gw_log (GW_LOG_DEBUG, "main", "reading kernel resource, target %s",
- target);
- if (lang)
- gw_log (GW_LOG_DEBUG, "main", "reading kernel resource, lang %s",
- lang);
- if (kernel_res)
- gw_res_close (kernel_res);
- kernel_res = gw_res_init ();
- if (gw_res_merge (kernel_res, default_res))
- {
- gw_log (GW_LOG_WARN, "main", "Couldn't read resource file %s",
- default_res);
+ user_set_init ();
+
+ if (info.bibset)
+ ccl_qual_rm (&info.bibset);
+ info.bibset = ccl_qual_mk ();
+
+ if (info.kernel_res)
+ gw_res_close (info.kernel_res);
+ info.kernel_res = gw_res_init ();
+
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, default %s",
+ info.default_res);
+ if (*info.target)
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, target %s",
+ info.target);
+ if (info.lang)
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading kernel resource, lang %s",
+ info.lang);
+
+ /* read default resources. These should exist */
+ if (gw_res_merge (info.kernel_res, info.default_res))
+ {
+ gw_log (GW_LOG_WARN, KERNEL_LOG, "Couldn't read resource file %s",
+ info.default_res);
return;
}
- strcpy (path_prefix, gw_res_get (kernel_res, "gw.path", "."));
+ strcpy (path_prefix, gw_res_get (info.kernel_res, "gw.path", "."));
- if (target)
+ /* fetch target definitions (if defined at all) */
+ if (*info.target)
{
- sprintf (resource_name, "gw.target.%s", target);
- v = gw_res_get (kernel_res, resource_name, NULL);
+ sprintf (resource_name, "gw.target.%s", info.target);
+ v = gw_res_get (info.kernel_res, resource_name, NULL);
if (v)
{
sprintf (fname, "%s/%s", path_prefix, v);
- gw_res_merge (kernel_res, fname);
+ gw_res_merge (info.kernel_res, fname);
}
- }
- if (lang)
+ }
+ /* fetch user definitions (if user-id is specified) */
+ if (info.userid >= 0)
{
- sprintf (resource_name, "gw.lang.%s", lang);
- v = gw_res_get (kernel_res, resource_name, NULL);
+ sprintf (fname, "%s/user.%d.r", path_prefix, info.userid);
+ gw_res_merge (info.kernel_res, fname);
+ }
+ /* fetch language definitions (if specified at all) */
+ v = gw_res_get (info.kernel_res, "gw.language", info.lang);
+ if (v)
+ {
+ sprintf (resource_name, "gw.lang.%s", v);
+ v = gw_res_get (info.kernel_res, resource_name, NULL);
if (v)
{
sprintf (fname, "%s/%s", path_prefix, v);
- gw_res_merge (kernel_res, fname);
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Reading language resources %s",
+ fname);
+ gw_res_merge (info.kernel_res, fname);
}
}
- v = gw_res_get (kernel_res, "gw.bibset", NULL);
+ /* fetch overriding resources from file (if specified) */
+ if (info.override_res)
+ {
+ sprintf (fname, "%s/%s", path_prefix, info.override_res);
+ gw_res_merge (info.kernel_res, fname);
+ }
+
+ /* read bibset definition for ccl */
+ v = gw_res_get (info.kernel_res, "gw.bibset", NULL);
if (v)
{
FILE *bib_inf;
sprintf (fname, "%s/%s", path_prefix, v);
bib_inf = fopen (fname, "r");
if (!bib_inf)
- gw_log (GW_LOG_WARN, "main", "cannot open %s", fname);
+ gw_log (GW_LOG_WARN, KERNEL_LOG, "cannot open %s", fname);
else
{
- gw_log (GW_LOG_DEBUG, "main", "reading bib file %s", fname);
- ccl_qual_file (bibset, bib_inf);
+ gw_log (GW_LOG_DEBUG, KERNEL_LOG, "reading bib file %s", fname);
+ ccl_qual_file (info.bibset, bib_inf);
fclose (bib_inf);
}
}
+
+ /* determine host name and port no */
+ sprintf (resource_name, "gw.target.%s", info.target);
+ if (*info.target && ! gw_res_get (info.kernel_res, resource_name, NULL))
+ {
+ /* target is specified, and there is no sub-resource for it... */
+ const char *split;
+
+ if ((split = strchr (info.target, ':')))
+ {
+ memcpy (info.hostname, info.target, split-info.target);
+ info.hostname[split-info.target] = '\0';
+ info.port = atoi (split+1);
+ }
+ else
+ {
+ strcpy (info.hostname, info.target);
+ info.port = gw_res_int (info.kernel_res, "gw.portno", 210);
+ }
+ }
+ else
+ { /* resources gw.hostname and gw.portno will be used */
+ strncpy (info.hostname, gw_res_get (info.kernel_res,
+ "gw.hostname", "localhost"),
+ sizeof(info.hostname)-1);
+ info.port = gw_res_int (info.kernel_res, "gw.portno", 210);
+ strcpy (info.account, gw_res_get (info.kernel_res, "gw.account", ""));
+ }
+ /* set info.databases (all available databases for target) */
+ /* set info.database (first database for target) */
+ if (info.databases)
+ free (info.databases);
+ if (info.database)
+ free (info.database);
+ v = gw_res_get (info.kernel_res, "gw.databases", "");
+ info.databases = gw_strdup (v);
+ for (cp = info.databases; (cp = strchr (cp, ' ')); cp++)
+ *cp = ',';
+ v = gw_res_get (info.kernel_res, "gw.database", "");
+ if (*v == '\0' && *info.databases)
+ {
+ int len;
+ cp = strchr (info.databases, ',');
+
+ len = cp ? (cp-info.databases) : strlen (info.databases);
+ info.database = malloc (len+1);
+ assert (info.database);
+ memcpy (info.database, info.databases, len);
+ info.database[len] = '\0';
+ }
+ else
+ {
+ info.database = gw_strdup (v);
+ for (cp = info.database; (cp = strchr (cp, ' ')); cp++)
+ *cp = ',';
+ }
+
+ /* the port no can be explicitly overridden by a command line option */
+ if (info.override_portno)
+ info.port = atoi (info.override_portno);
+
+ /* the hostname can be explicitly overridden by a command line option */
+ if (info.override_hostname)
+ strncpy (info.hostname, info.override_hostname,
+ sizeof(info.hostname)-1);
+
+ ccl_token_and = gw_res_get (info.kernel_res, "ccl.token.and", "and");
+ ccl_token_or = gw_res_get (info.kernel_res, "ccl.token.or", "or");
+ ccl_token_not = gw_res_get (info.kernel_res, "ccl.token.not", "not");
+ ccl_token_set = gw_res_get (info.kernel_res, "ccl.token.set", "set");
+
+ /* determine if more than one result-set names is supported */
+ if (gw_res_bool (info.kernel_res, "gw.result.set", 1))
+ info.setno = 0;
+ else
+ info.setno = -1;
+#if USE_FML
+ if (!info.fml)
+ {
+ v = gw_res_get (info.kernel_res, "gw.fml", "default.fml");
+ sprintf (fname, "%s/%s", path_prefix, v);
+ fml_inf = fopen (fname, "r");
+ if (!fml_inf)
+ gw_log (GW_LOG_WARN, KERNEL_LOG,
+ "cannot open fml script %s", fname);
+ else
+ {
+ info.fml = fml_open ();
+ info.fml->read_func = fml_inf_read;
+ info.fml->write_func = fml_inf_write;
+ fml_preprocess (info.fml);
+ fml_exec (info.fml);
+ fclose (fml_inf);
+ }
+ }
+#endif
}