First work on resource monitor program.
[egate.git] / kernel / persist.c
1 /* Gateway kernel - Z39.50 Persistence
2  * Europagate, 1995
3  *
4  * $Log: persist.c,v $
5  * Revision 1.4  1995/04/20 16:10:46  adam
6  * Modified to work with non-blocking zass-api. Not using non-blocking
7  * facility yet.
8  *
9  * Revision 1.3  1995/04/19  13:19:09  adam
10  * New command: account - for authentication.
11  *
12  * Revision 1.2  1995/04/19  10:46:19  adam
13  * Persistency works much better now. New command: status - history-like
14  *
15  * Revision 1.1  1995/04/19  07:31:10  adam
16  * First work on Z39.50 persistence.
17  *
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27
28 #include "kernel.h"
29
30 static int fgetsx (char *buf, int size, FILE *inf)
31 {
32     char *cp;
33
34     if (!fgets (buf, size, inf))
35         return 0;
36     if ((cp = strchr (buf, '\n')))
37         *cp = '\0';
38     return 1;
39 }
40
41 static int set_change;
42
43 static int obtain_set (ZASS zass, struct gw_user_set *set)
44 {
45     const struct zass_searchent *p;
46
47     p = zass_search (zass, set->rpn, set->name, set->database, NULL);
48     if (!p)
49         return 2;
50     if (p->errcode != -1)
51         return 3;
52     if (p->num != set->hits)
53         set_change = 1;
54     set->present_flag = 1;
55     set->hits = p->num;
56     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s researched", set->name);
57     return 0;
58 }
59
60 static int obtain_sets (ZASS zass, struct ccl_rpn_node *rpn, 
61                         struct gw_user_set *sets)
62 {
63     struct gw_user_set *set;
64     int r;
65
66     switch (rpn->kind)
67     {
68     case CCL_RPN_AND:
69     case CCL_RPN_OR:
70     case CCL_RPN_NOT:
71     case CCL_RPN_PROX:
72         if ((r=obtain_sets (zass, rpn->u.p[0], sets)))
73             return r;
74         return obtain_sets (zass, rpn->u.p[1], sets);
75     case CCL_RPN_TERM:
76         return 0;
77     case CCL_RPN_SET:
78         set = user_set_search (rpn->u.setname);
79         if (!set)
80         {
81             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s not there at all",
82                     rpn->u.setname);
83             return 1;
84         }
85         if (set->present_flag)
86         {
87             gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Set %s already there",
88                     rpn->u.setname);
89             return 0;
90         }
91     }
92     return obtain_set (zass, set);
93 }
94
95 const struct zass_searchent *zass_p_search (ZASS zass, 
96                         struct ccl_rpn_node *rpn, 
97                         const char *result_set,
98                         const char *database,
99                         struct gw_user_set *sets)
100 {
101     int r;
102
103     set_change = 0;
104     r = obtain_sets (zass, rpn, sets);
105     if (r)
106         return NULL;
107     return zass_search (zass, rpn, (char*) result_set, (char*) database, NULL);
108 }
109
110 const struct zass_presentent *zass_p_present (ZASS zass,
111                         const char *result_set, int offset, int number)
112 {
113     struct gw_user_set *set;
114
115     set = user_set_search (result_set);
116     if (!set)
117         return NULL;
118     if (!set->present_flag)
119     {
120         const struct zass_searchent *p;
121
122         p = zass_p_search (zass, set->rpn, result_set, set->database,
123                            info.sets);
124         if (!p)
125             return NULL;
126     }
127     return zass_present (zass, (char*) result_set, offset, number, NULL);
128 }
129
130 struct ccl_rpn_node *load_rpn (char *buf, FILE *inf)
131 {
132     struct ccl_rpn_node *rpn;
133     struct ccl_rpn_attr **attrp;
134     int type, value, no_read;
135     char *cp;
136
137     if (!fgetsx (buf, 1024, inf))
138         return NULL;
139     rpn = malloc (sizeof (*rpn));
140     if (!rpn)
141         return NULL;
142     switch (*buf)
143     {
144     case 'A':
145         rpn->kind = CCL_RPN_AND;
146         rpn->u.p[0] = load_rpn (buf, inf);
147         rpn->u.p[1] = load_rpn (buf, inf);
148         break;
149     case 'O':
150         rpn->kind = CCL_RPN_OR;
151         rpn->u.p[0] = load_rpn (buf, inf);
152         rpn->u.p[1] = load_rpn (buf, inf);
153         break;
154     case 'N':
155         rpn->kind = CCL_RPN_NOT;
156         rpn->u.p[0] = load_rpn (buf, inf);
157         rpn->u.p[1] = load_rpn (buf, inf);
158         break;
159     case 'P':
160         rpn->kind = CCL_RPN_PROX;
161         rpn->u.p[0] = load_rpn (buf, inf);
162         rpn->u.p[1] = load_rpn (buf, inf);
163         break;
164     case 'T':
165         rpn->kind = CCL_RPN_TERM;
166
167         rpn->u.t.term = gw_strdup (buf+2);
168         attrp = &rpn->u.t.attr_list;
169         if (!fgetsx (buf, 1024, inf))
170             return NULL;
171         cp = buf;
172         while (sscanf (cp, "%d %d%n", &type, &value, &no_read) > 1)
173         {
174             *attrp = malloc (sizeof(**attrp));
175             (*attrp)->type = type;
176             (*attrp)->value = value;
177             attrp = &(*attrp)->next;
178             cp += no_read; 
179         }
180         *attrp = NULL;
181         break;
182     case 'S':
183         rpn->kind = CCL_RPN_SET;
184         rpn->u.setname = gw_strdup (buf+2);
185         break;
186     default:
187         free (rpn);
188         return NULL;
189     }
190     return rpn;
191 }
192
193 int load_p_state (int userid)
194 {
195     FILE *inf;
196     char fname[128];
197     char fline[1025];
198     char database[1024];
199     char resultname[32];
200     int hits;
201     struct gw_user_set *set;
202
203     sprintf (fname, "persist.%d", userid);
204
205     inf = fopen (fname, "r");
206     if (!inf)
207     {
208         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
209                 "Couldn't open %s", fname);
210         return -1;
211     }
212     gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
213        "Reading persistence file %s", fname);
214
215     if (!fgetsx (fline, 1024, inf))
216         return -1;
217     if (sscanf (fline, "%s", info.target) != 1)
218         *info.target = '\0';
219     read_kernel_res ();
220
221     if (!fgetsx (fline, 1024, inf))
222         return -1;
223     if (sscanf (fline, "%s", info.account) != 1)
224         *info.account = '\0';
225    
226     if (!fgetsx (fline, 1024, inf))
227         return -1;
228     free (info.database);
229     info.database = gw_strdup (fline);
230
231     if (!fgetsx (fline, 1024, inf))
232         return -1;
233     if (sscanf (fline, "%d", &info.setno) != 1)
234         return -1;
235     gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
236            "Reading persistence file %s (2)", fname);
237     reopen_target ();
238     while (fgetsx (fline, 1024, inf))
239     {
240         gw_log (GW_LOG_DEBUG, KERNEL_LOG, 
241               "Reading persistence file %s (3)", fname);
242         if (sscanf (fline, "%s %d %s", resultname, &hits, database) != 3)
243             return -1;
244         if (!fgetsx (fline, 1024, inf))        /* search string */
245             return -1;
246         gw_log (GW_LOG_DEBUG, KERNEL_LOG,
247                 "Adding %s, %d hits, database %s",
248                 resultname, hits, database);
249         gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Search string %s", fline);
250         set = user_set_add (resultname, hits, database, NULL, 0, fline);
251         set->rpn = load_rpn (fline, inf);
252         ccl_pr_tree (set->rpn, stderr);
253         fgetsx (fline, 1024, inf);
254     }
255     fclose (inf);
256     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Finished reading %s", fname);
257     return 0;
258 }
259
260 static void save_rpn (struct ccl_rpn_node *rpn, FILE *of)
261 {
262     struct ccl_rpn_attr *attr;
263
264     switch (rpn->kind)
265     {
266     case CCL_RPN_AND:
267         fprintf (of, "A\n");
268         save_rpn (rpn->u.p[0], of);
269         save_rpn (rpn->u.p[1], of);
270         break;
271     case CCL_RPN_OR:
272         fprintf (of, "O\n");
273         save_rpn (rpn->u.p[0], of);
274         save_rpn (rpn->u.p[1], of);
275         break;
276     case CCL_RPN_NOT:
277         fprintf (of, "N\n");
278         save_rpn (rpn->u.p[0], of);
279         save_rpn (rpn->u.p[1], of);
280         break;
281     case CCL_RPN_PROX:
282         fprintf (of, "P\n");
283         save_rpn (rpn->u.p[0], of);
284         save_rpn (rpn->u.p[1], of);
285         break;
286     case CCL_RPN_TERM:
287         fprintf (of, "T %s\n", rpn->u.t.term);
288         for (attr = rpn->u.t.attr_list; attr; attr = attr->next)
289             fprintf (of, "%d %d ", attr->type, attr->value);
290         fprintf (of, "\n");
291         break;
292     case CCL_RPN_SET:
293         fprintf (of, "S %s\n", rpn->u.setname); 
294     }
295 }
296
297 static void save_sets (FILE *of, struct gw_user_set *sp)
298 {
299     if (!sp)
300         return;
301     save_sets (of, sp->prev);
302     fprintf (of, "%s %d %s\n%s\n", sp->name, sp->hits, sp->database,
303              sp->search_str);
304     save_rpn (sp->rpn, of);
305     fprintf (of, "X\n");
306 }
307
308 int save_p_state (int userid)
309 {
310     FILE *of;
311     char fname[128];
312
313     sprintf (fname, "persist.%d", userid);
314
315     of = fopen (fname, "w");
316     if (!of)
317     {
318         gw_log (GW_LOG_WARN|GW_LOG_ERRNO, KERNEL_LOG, 
319                 "Couldn't open %s", fname);
320         return -1;
321     }
322     gw_log (GW_LOG_DEBUG, KERNEL_LOG, "Writing persistence file %s", fname);
323     fprintf (of, "%s\n%s\n%s\n%d\n", info.target, info.account,
324              info.database, info.setno);
325     save_sets (of, info.sets);
326     fclose (of);
327     return 0;
328 }