Revise resource API to take default/override resources.
[idzebra-moved-to-github.git] / index / zserver.c
1 /* $Id: zserver.c,v 1.113 2004-01-22 11:27:21 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <stdio.h>
24 #include <assert.h>
25 #include <fcntl.h>
26 #ifdef WIN32
27 #include <io.h>
28 #include <process.h>
29 #include <sys/locking.h>
30 #else
31 #include <unistd.h>
32 #endif
33
34 #include <errno.h>
35 #include <yaz/log.h>
36 #include <yaz/ill.h>
37 #include <yaz/yaz-util.h>
38
39 #include <sys/types.h>
40
41 #include "zserver.h"
42
43 static int bend_sort (void *handle, bend_sort_rr *rr);
44 static int bend_delete (void *handle, bend_delete_rr *rr);
45 static int bend_esrequest (void *handle, bend_esrequest_rr *rr);
46 static int bend_segment (void *handle, bend_segment_rr *rr);
47 static int bend_search (void *handle, bend_search_rr *r);
48 static int bend_fetch (void *handle, bend_fetch_rr *r);
49 static int bend_scan (void *handle, bend_scan_rr *r);
50
51 bend_initresult *bend_init (bend_initrequest *q)
52 {
53     bend_initresult *r = (bend_initresult *)
54         odr_malloc (q->stream, sizeof(*r));
55     ZebraHandle zh;
56     struct statserv_options_block *sob;
57     char *user = NULL;
58     char *passwd = NULL;
59
60     r->errcode = 0;
61     r->errstring = 0;
62     q->bend_sort = bend_sort;
63     q->bend_delete = bend_delete;
64     q->bend_esrequest = bend_esrequest;
65     q->bend_segment = bend_segment;
66     q->bend_search = bend_search;
67     q->bend_fetch = bend_fetch;
68     q->bend_scan = bend_scan;
69
70     q->implementation_name = "Zebra Information Server";
71     q->implementation_version = "Zebra " ZEBRAVER;
72
73     yaz_log (LOG_DEBUG, "bend_init");
74
75     sob = statserv_getcontrol ();
76     if (!(zh = zebra_open (sob->handle)))
77     {
78         yaz_log (LOG_WARN, "Failed to read config `%s'", sob->configname);
79         r->errcode = 1;
80         return r;
81     }
82     if (q->auth)
83     {
84         if (q->auth->which == Z_IdAuthentication_open)
85         {
86             char *openpass = xstrdup (q->auth->u.open);
87             char *cp = strchr (openpass, '/');
88             if (cp)
89             {
90                 *cp = '\0';
91                 user = nmem_strdup (odr_getmem (q->stream), openpass);
92                 passwd = nmem_strdup (odr_getmem (q->stream), cp+1);
93             }
94             xfree (openpass);
95         }
96     }
97     if (zebra_auth (zh, user, passwd))
98     {
99         r->errcode = 222;
100         r->errstring = user;
101         zebra_close (zh);
102         return r;
103     }
104     r->handle = zh;
105     if (q->charneg_request) /* characater set and langauge negotiation? */
106     {
107         char **charsets = 0;
108         int num_charsets;
109         char **langs = 0;
110         int num_langs = 0;
111         int selected = 0;
112         int i;
113         NMEM nmem = nmem_create();
114
115         yaz_log (LOG_LOG, "character set and language negotiation");
116
117         yaz_get_proposal_charneg (nmem, q->charneg_request,
118                                   &charsets, &num_charsets,
119                                   &langs, &num_langs, &selected);
120         
121         for (i = 0; i < num_charsets; i++)
122         {
123             const char *right_name = "";
124             /*
125              * FIXME! It is like rudiment :-))
126              * We have to support this short names of character sets,
127              * because a lot servers in Russia to use own in during
128              * character set and language negotiation still.
129              */
130             
131             if (!yaz_matchstr(charsets[i], "win")) {
132                 right_name = "WINDOWS-1251";
133             } else if (!yaz_matchstr(charsets[i], "koi")) {
134                 right_name = "KOI8-R";
135             } else if (!yaz_matchstr(charsets[i], "iso")) {
136                 right_name = "ISO-8859-5";
137             } else if (!yaz_matchstr(charsets[i], "dos")) {
138                 right_name = "CP866";
139             } else if (!yaz_matchstr(charsets[i], "uni")) {
140                 right_name = "UTF-8";
141             } else {
142                 right_name = charsets[i];
143             }
144             if (odr_set_charset (q->decode, "UTF-8", right_name) == 0)
145             {
146                 yaz_log (LOG_LOG, "charset %d %s (proper name %s): OK", i,
147                          charsets[i], right_name);
148                 odr_set_charset (q->stream, right_name, "UTF-8");
149                 if (selected)
150                     zebra_record_encoding (zh, right_name);
151                 q->charneg_response =
152                     yaz_set_response_charneg (q->stream, charsets[i],
153                                               0, selected);
154                 break;
155             } else {
156                 yaz_log (LOG_LOG, "charset %d %s (proper name %s): unsupported", i,
157                          charsets[i], right_name);
158             }
159         }
160         nmem_destroy(nmem);
161     }
162     return r;
163 }
164
165 static void search_terms (ZebraHandle zh, bend_search_rr *r)
166 {
167     int count;
168     int no_terms;
169     int i;
170     int type;
171     struct Z_External *ext;
172     Z_SearchInfoReport *sr;
173
174     /* get no of terms for result set */
175     no_terms = zebra_resultSetTerms (zh, r->setname, 0, 0, 0, 0, 0);
176     if (!no_terms)
177         return;
178
179     r->search_info = odr_malloc (r->stream, sizeof(*r->search_info));
180
181     r->search_info->num_elements = 1;
182     r->search_info->list =
183         odr_malloc (r->stream, sizeof(*r->search_info->list));
184     r->search_info->list[0] =
185         odr_malloc (r->stream, sizeof(**r->search_info->list));
186     r->search_info->list[0]->category = 0;
187     r->search_info->list[0]->which = Z_OtherInfo_externallyDefinedInfo;
188     ext = odr_malloc (r->stream, sizeof(*ext));
189     r->search_info->list[0]->information.externallyDefinedInfo = ext;
190     ext->direct_reference =
191         yaz_oidval_to_z3950oid (r->stream, CLASS_USERINFO, VAL_SEARCHRES1);
192     ext->indirect_reference = 0;
193     ext->descriptor = 0;
194     ext->which = Z_External_searchResult1;
195     sr = odr_malloc (r->stream, sizeof(Z_SearchInfoReport));
196     ext->u.searchResult1 = sr;
197     sr->num = no_terms;
198     sr->elements = odr_malloc (r->stream, sr->num *
199                                sizeof(*sr->elements));
200     for (i = 0; i<no_terms; i++)
201     {
202         Z_Term *term;
203         char outbuf[1024];
204         size_t len = sizeof(outbuf);
205         zebra_resultSetTerms (zh, r->setname, i,
206                               &count, &type, outbuf, &len);
207         
208         sr->elements[i] = odr_malloc (r->stream, sizeof(**sr->elements));
209         sr->elements[i]->subqueryId = 0;
210         sr->elements[i]->fullQuery = odr_malloc (r->stream, 
211                                                  sizeof(bool_t));
212         *sr->elements[i]->fullQuery = 0;
213         sr->elements[i]->subqueryExpression = 
214             odr_malloc (r->stream, sizeof(Z_QueryExpression));
215         sr->elements[i]->subqueryExpression->which = 
216             Z_QueryExpression_term;
217         sr->elements[i]->subqueryExpression->u.term =
218             odr_malloc (r->stream, sizeof(Z_QueryExpressionTerm));
219         term = odr_malloc (r->stream, sizeof(Z_Term));
220         sr->elements[i]->subqueryExpression->u.term->queryTerm = term;
221         switch (type)
222         {
223         case Z_Term_characterString:
224             yaz_log (LOG_DEBUG, "term as characterString");
225             term->which = Z_Term_characterString;
226             term->u.characterString = odr_strdup (r->stream, outbuf);
227             break;
228         case Z_Term_general:
229             yaz_log (LOG_DEBUG, "term as general");
230             term->which = Z_Term_general;
231             term->u.general = odr_malloc (r->stream, sizeof(*term->u.general));
232             term->u.general->size = term->u.general->len = len;
233             term->u.general->buf = odr_malloc (r->stream, len);
234             memcpy (term->u.general->buf, outbuf, len);
235             break;
236         default:
237             term->which = Z_Term_general;
238             term->u.null = odr_nullval();
239         }
240         sr->elements[i]->subqueryExpression->u.term->termComment = 0;
241         sr->elements[i]->subqueryInterpretation = 0;
242         sr->elements[i]->subqueryRecommendation = 0;
243         sr->elements[i]->subqueryCount = odr_intdup (r->stream, count);
244         sr->elements[i]->subqueryWeight = 0;
245         sr->elements[i]->resultsByDB = 0;
246     }
247 }
248
249 int bend_search (void *handle, bend_search_rr *r)
250 {
251     ZebraHandle zh = (ZebraHandle) handle;
252
253     r->hits = 0;
254     r->errcode = 0;
255     r->errstring = NULL;
256     
257     if (zebra_select_databases (zh, r->num_bases,
258                                 (const char **) r->basenames))
259     {
260         zebra_result (zh, &r->errcode, &r->errstring);
261         return 0;
262     }
263     yaz_log (LOG_LOG, "ResultSet '%s'", r->setname);
264     switch (r->query->which)
265     {
266     case Z_Query_type_1: case Z_Query_type_101:
267         zebra_search_RPN (zh, r->stream, r->query->u.type_1,
268                           r->setname, &r->hits);
269         zebra_result (zh, &r->errcode, &r->errstring);
270         if (!r->errcode)
271             search_terms (zh, r);
272         break;
273     case Z_Query_type_2:
274         r->errcode = 107;
275         r->errstring = "type-2";
276         break;
277     default:
278         r->errcode = 107;
279     }
280     return 0;
281 }
282
283
284 int bend_fetch (void *handle, bend_fetch_rr *r)
285 {
286     ZebraHandle zh = (ZebraHandle) handle;
287     ZebraRetrievalRecord retrievalRecord;
288
289     retrievalRecord.position = r->number;
290     
291     r->last_in_set = 0;
292     zebra_records_retrieve (zh, r->stream, r->setname, r->comp,
293                             r->request_format, 1, &retrievalRecord);
294     zebra_result (zh, &r->errcode, &r->errstring);
295     /*  non Surrogate Diagnostic OR Surrogate Diagnostic */
296     if (r->errcode == 0 && retrievalRecord.errCode)
297     {
298         r->surrogate_flag = 1;
299         r->errcode = retrievalRecord.errCode;
300         r->errstring = retrievalRecord.errString;
301         r->basename = retrievalRecord.base;
302     }
303     else if (r->errcode == 0)        /* Database Record */
304     {
305         r->errcode = 0;
306         r->basename = retrievalRecord.base;
307         r->record = retrievalRecord.buf;
308         r->len = retrievalRecord.len;
309         r->output_format = retrievalRecord.format;
310     }
311     return 0;
312 }
313
314 static int bend_scan (void *handle, bend_scan_rr *r)
315 {
316     ZebraScanEntry *entries;
317     ZebraHandle zh = (ZebraHandle) handle;
318     int is_partial, i;
319
320     if (zebra_select_databases (zh, r->num_bases, 
321                                 (const char **) r->basenames))
322     {
323         zebra_result (zh, &r->errcode, &r->errstring);
324         return 0;
325     }
326     r->entries = (struct scan_entry *)
327         odr_malloc (r->stream, sizeof(*r->entries) * r->num_entries);
328     zebra_scan (zh, r->stream, r->term,
329                 r->attributeset,
330                 &r->term_position,
331                 &r->num_entries, &entries, &is_partial);
332     if (is_partial)
333         r->status = BEND_SCAN_PARTIAL;
334     else
335         r->status = BEND_SCAN_SUCCESS;
336     for (i = 0; i < r->num_entries; i++)
337     {
338         r->entries[i].term = entries[i].term;
339         r->entries[i].occurrences = entries[i].occurrences;
340     }
341     zebra_result (zh, &r->errcode, &r->errstring);
342     return 0;
343 }
344
345 void bend_close (void *handle)
346 {
347     zebra_close ((ZebraHandle) handle);
348     xmalloc_trav("bend_close");
349     nmem_print_list();
350 }
351
352 int bend_sort (void *handle, bend_sort_rr *rr)
353 {
354     ZebraHandle zh = (ZebraHandle) handle;
355
356     zebra_sort (zh, rr->stream,
357                 rr->num_input_setnames, (const char **) rr->input_setnames,
358                 rr->output_setname, rr->sort_sequence, &rr->sort_status);
359     zebra_result (zh, &rr->errcode, &rr->errstring);
360     return 0;
361 }
362
363 int bend_delete (void *handle, bend_delete_rr *rr)
364 {
365     ZebraHandle zh = (ZebraHandle) handle;
366
367     rr->delete_status = zebra_deleleResultSet(zh, rr->function,
368                                               rr->num_setnames, rr->setnames,
369                                               rr->statuses);
370     return 0;
371 }
372
373 static int es_admin_request (ZebraHandle zh, Z_AdminEsRequest *r)
374 {
375     switch (r->toKeep->which)
376     {
377     case Z_ESAdminOriginPartToKeep_reIndex:
378         yaz_log(LOG_LOG, "adm-reindex");
379         break;
380     case Z_ESAdminOriginPartToKeep_truncate:
381         yaz_log(LOG_LOG, "adm-truncate");
382         break;
383     case Z_ESAdminOriginPartToKeep_drop:
384         yaz_log(LOG_LOG, "adm-drop");
385         zebra_drop_database (zh, r->toKeep->databaseName);
386         break;
387     case Z_ESAdminOriginPartToKeep_create:
388         yaz_log(LOG_LOG, "adm-create %s", r->toKeep->databaseName);
389         zebra_create_database (zh, r->toKeep->databaseName);
390         break;
391     case Z_ESAdminOriginPartToKeep_import:
392         yaz_log(LOG_LOG, "adm-import");
393         zebra_admin_import_begin (zh, r->toKeep->databaseName,
394                         r->toKeep->u.import->recordType);
395         break;
396     case Z_ESAdminOriginPartToKeep_refresh:
397         yaz_log(LOG_LOG, "adm-refresh");
398         break;
399     case Z_ESAdminOriginPartToKeep_commit:
400         yaz_log(LOG_LOG, "adm-commit");
401         break;
402     case Z_ESAdminOriginPartToKeep_shutdown:
403         yaz_log(LOG_LOG, "shutdown");
404         zebra_admin_shutdown(zh);
405         break;
406     case Z_ESAdminOriginPartToKeep_start:
407         yaz_log(LOG_LOG, "start");
408         zebra_admin_start(zh);
409         break;
410     default:
411         yaz_log(LOG_LOG, "unknown admin");
412     }
413     if (r->toKeep->databaseName)
414     {
415         yaz_log(LOG_LOG, "database %s", r->toKeep->databaseName);
416     }
417     return 0;
418 }
419
420 static int es_admin (ZebraHandle zh, Z_Admin *r)
421 {
422     switch (r->which)
423     {
424     case Z_Admin_esRequest:
425         es_admin_request (zh, r->u.esRequest);
426         break;
427     case Z_Admin_taskPackage:
428         yaz_log (LOG_LOG, "adm taskpackage (unhandled)");
429         break;
430     default:
431         break;
432     }
433
434     return 0;
435 }
436
437 int bend_segment (void *handle, bend_segment_rr *rr)
438 {
439     ZebraHandle zh = (ZebraHandle) handle;
440     Z_Segment *segment = rr->segment;
441
442     if (segment->num_segmentRecords)
443         zebra_admin_import_segment (zh, rr->segment);
444     else
445         zebra_admin_import_end (zh);
446     return 0;
447 }
448
449 int bend_esrequest (void *handle, bend_esrequest_rr *rr)
450 {
451     ZebraHandle zh = (ZebraHandle) handle;
452     
453     yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
454     if (rr->esr->packageName)
455         yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
456     yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
457
458     if (!rr->esr->taskSpecificParameters)
459     {
460         yaz_log (LOG_WARN, "No task specific parameters");
461     }
462     else if (rr->esr->taskSpecificParameters->which == Z_External_ESAdmin)
463     {
464         es_admin (zh, rr->esr->taskSpecificParameters->u.adminService);
465
466         zebra_result (zh, &rr->errcode, &rr->errstring);
467     }
468     else if (rr->esr->taskSpecificParameters->which == Z_External_update)
469     {
470         Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
471         yaz_log (LOG_LOG, "Received DB Update");
472         if (up->which == Z_IUUpdate_esRequest)
473         {
474             Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
475             Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
476             Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
477             
478             yaz_log (LOG_LOG, "action");
479             if (toKeep->action)
480             {
481                 switch (*toKeep->action)
482                 {
483                 case Z_IUOriginPartToKeep_recordInsert:
484                     yaz_log (LOG_LOG, "recordInsert");
485                     break;
486                 case Z_IUOriginPartToKeep_recordReplace:
487                     yaz_log (LOG_LOG, "recordUpdate");
488                     break;
489                 case Z_IUOriginPartToKeep_recordDelete:
490                     yaz_log (LOG_LOG, "recordDelete");
491                     break;
492                 case Z_IUOriginPartToKeep_elementUpdate:
493                     yaz_log (LOG_LOG, "elementUpdate");
494                     break;
495                 case Z_IUOriginPartToKeep_specialUpdate:
496                     yaz_log (LOG_LOG, "specialUpdate");
497                     break;
498                 case Z_ESAdminOriginPartToKeep_shutdown:
499                     yaz_log (LOG_LOG, "shutDown");
500                     break;
501                 case Z_ESAdminOriginPartToKeep_start:
502                     yaz_log (LOG_LOG, "start");
503                     break;
504                 default:
505                     yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
506                 }
507             }
508             if (toKeep->databaseName)
509             {
510                 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
511
512                 if (zebra_select_database(zh, toKeep->databaseName))
513                     return 0;
514             }
515             else
516             {
517                 yaz_log (LOG_WARN, "no database supplied for ES Update");
518                 rr->errcode = 1008;
519                 rr->errstring = "database";
520                 return 0;
521             }
522             if (notToKeep)
523             {
524                 int i;
525                 zebra_begin_trans (zh, 1);
526                 for (i = 0; i < notToKeep->num; i++)
527                 {
528                     Z_External *rec = notToKeep->elements[i]->record;
529                     struct oident *oident = 0;
530                     Odr_oct *opaque_recid = 0;
531                     int sysno = 0;
532
533                     if (notToKeep->elements[i]->u.opaque)
534                     {
535                         switch(notToKeep->elements[i]->which)
536                         {
537                         case Z_IUSuppliedRecords_elem_opaque:
538                             opaque_recid = notToKeep->elements[i]->u.opaque;
539                             break; /* OK, recid already set */
540                         case Z_IUSuppliedRecords_elem_number:
541                             sysno = *notToKeep->elements[i]->u.number;
542                             break;
543                         }
544                     }
545                     if (rec->direct_reference)
546                     {
547                         oident = oid_getentbyoid(rec->direct_reference);
548                         if (oident)
549                             yaz_log (LOG_LOG, "record %d type %s", i,
550                                      oident->desc);
551                     }
552                     switch (rec->which)
553                     {
554                     case Z_External_sutrs:
555                         if (rec->u.octet_aligned->len > 170)
556                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
557                                      rec->u.sutrs->len,
558                                      rec->u.sutrs->buf);
559                         else
560                             yaz_log (LOG_LOG, "%d bytes:\n%s",
561                                      rec->u.sutrs->len,
562                                      rec->u.sutrs->buf);
563                         break;
564                     case Z_External_octet:
565                         if (rec->u.octet_aligned->len > 170)
566                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
567                                      rec->u.octet_aligned->len,
568                                      rec->u.octet_aligned->buf);
569                         else
570                             yaz_log (LOG_LOG, "%d bytes\n%s",
571                                      rec->u.octet_aligned->len,
572                                      rec->u.octet_aligned->buf);
573                     }
574                     if (oident && oident->value != VAL_TEXT_XML)
575                     {
576                         rr->errcode = 224;
577                         rr->errstring = "only XML update supported";
578                         break;
579                     }
580                     if (rec->which == Z_External_octet)
581                     {
582                         int action = 0;
583
584                         if (*toKeep->action ==
585                             Z_IUOriginPartToKeep_recordInsert)
586                             action = 1;
587                         if (*toKeep->action ==
588                             Z_IUOriginPartToKeep_recordReplace)
589                             action = 2;
590                         if (*toKeep->action ==
591                             Z_IUOriginPartToKeep_recordDelete)
592                             action = 3;
593                         if (*toKeep->action ==
594                             Z_IUOriginPartToKeep_specialUpdate)
595                             action = 4;
596
597                         if (!action)
598                         {
599                             rr->errcode = 224;
600                             rr->errstring = "unsupported ES Update action";
601                             break;
602                         }
603                         else if (opaque_recid)
604                         {
605                             int r = zebra_admin_exchange_record (
606                                 zh,
607                                 rec->u.octet_aligned->buf,
608                                 rec->u.octet_aligned->len,
609                                 opaque_recid->buf, opaque_recid->len,
610                                 action);
611                             if (r)
612                             {
613                                 rr->errcode = 224;
614                                 rr->errstring = "record exchange failed";
615                                 break;
616                             }
617                         }
618                         else
619                         {
620                             int r = -1;
621                             switch(action) {
622                             case 1:
623                                 r = zebra_insert_record(
624                                     zh,
625                                     0, /* recordType */
626                                     &sysno,
627                                     0, /* match */
628                                     0, /* fname */
629                                     rec->u.octet_aligned->buf,
630                                     rec->u.octet_aligned->len);
631                                 if (r)
632                                 {
633                                     rr->errcode = 224;
634                                     rr->errstring = "insert_record failed";
635                                 }
636                                 break;
637                             case 2:
638                             case 4:
639                                 r = zebra_update_record(
640                                     zh,
641                                     0, /* recordType */
642                                     &sysno,
643                                     0, /* match */
644                                     0, /* fname */
645                                     rec->u.octet_aligned->buf,
646                                     rec->u.octet_aligned->len,
647                                     1);
648                                 if (r)
649                                 {
650                                     rr->errcode = 224;
651                                     rr->errstring = "update_record failed";
652                                 }
653                                 break;
654                             case 3:
655                                 r = zebra_delete_record(
656                                     zh,
657                                     0, /* recordType */
658                                     &sysno,
659                                     0, /* match */
660                                     0, /* fname */
661                                     rec->u.octet_aligned->buf,
662                                     rec->u.octet_aligned->len,
663                                     0);
664                                 if (r)
665                                 {
666                                     rr->errcode = 224;
667                                     rr->errstring = "delete_record failed";
668                                 }
669                                 break;
670                             }                           
671                         }
672                     }
673                 }
674                 zebra_end_trans (zh);
675             }
676         }
677     }
678     else
679     {
680         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
681                  rr->esr->taskSpecificParameters->which);
682         rr->errcode = 221;
683         
684     }
685     return 0;
686 }
687
688 static void bend_start (struct statserv_options_block *sob)
689 {
690     if (sob->handle)
691         zebra_stop((ZebraService) sob->handle);
692     sob->handle = zebra_start(sob->configname, 0, 0);
693     if (!sob->handle)
694     {
695         yaz_log (LOG_FATAL, "Failed to read config `%s'", sob->configname);
696         exit (1);
697     }
698 #ifdef WIN32
699     
700 #else
701     if (!sob->inetd) 
702     {
703         char pidfname[4096];
704         struct flock area;
705         int fd;
706
707         zebra_pidfname(sob->handle, pidfname);
708
709         fd = open (pidfname, O_EXCL|O_WRONLY|O_CREAT, 0666);
710         if (fd == -1)
711         {
712             if (errno != EEXIST)
713             {
714                 yaz_log(LOG_FATAL|LOG_ERRNO, "lock file %s", pidfname);
715                 exit(1);
716             }
717             fd = open(pidfname, O_RDWR, 0666);
718             if (fd == -1)
719             {
720                 yaz_log(LOG_FATAL|LOG_ERRNO, "lock file %s", pidfname);
721                 exit(1);
722             }
723         }
724         area.l_type = F_WRLCK;
725         area.l_whence = SEEK_SET;
726         area.l_len = area.l_start = 0L;
727         if (fcntl (fd, F_SETLK, &area) == -1)
728         {
729             yaz_log(LOG_ERRNO|LOG_FATAL, "Zebra server already running");
730             exit(1);
731         }
732         else
733         {
734             char pidstr[30];
735         
736             sprintf (pidstr, "%ld", (long) getpid ());
737             write (fd, pidstr, strlen(pidstr));
738         }
739     }
740 #endif
741 }
742
743 static void bend_stop(struct statserv_options_block *sob)
744 {
745 #ifdef WIN32
746
747 #else
748     if (!sob->inetd && sob->handle) 
749     {
750         char pidfname[4096];
751         zebra_pidfname(sob->handle, pidfname);
752         unlink (pidfname);
753     }
754 #endif
755     if (sob->handle)
756     {
757         ZebraService service = sob->handle;
758         zebra_stop(service);
759     }
760 }
761
762 int main (int argc, char **argv)
763 {
764     struct statserv_options_block *sob;
765
766     sob = statserv_getcontrol ();
767     strcpy (sob->configname, "zebra.cfg");
768     sob->bend_start = bend_start;
769     sob->bend_stop = bend_stop;
770 #ifdef WIN32
771     strcpy (sob->service_display_name, "Zebra Server");
772 #endif
773     statserv_setcontrol (sob);
774
775     return statserv_main (argc, argv, bend_init, bend_close);
776 }