Updated requires for RPM
[idzebra-moved-to-github.git] / index / zserver.c
1 /* $Id: zserver.c,v 1.91 2002-08-05 14:08:08 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
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
24
25 #include <stdio.h>
26 #include <assert.h>
27 #include <fcntl.h>
28 #ifdef WIN32
29 #include <io.h>
30 #include <process.h>
31 #else
32 #include <unistd.h>
33 #endif
34
35 #include <yaz/data1.h>
36 #ifdef ASN_COMPILED
37 #include <yaz/ill.h>
38 #endif
39
40 #include "zserver.h"
41
42 static int bend_sort (void *handle, bend_sort_rr *rr);
43 static int bend_delete (void *handle, bend_delete_rr *rr);
44 static int bend_esrequest (void *handle, bend_esrequest_rr *rr);
45 static int bend_segment (void *handle, bend_segment_rr *rr);
46 static int bend_search (void *handle, bend_search_rr *r);
47 static int bend_fetch (void *handle, bend_fetch_rr *r);
48 static int bend_scan (void *handle, bend_scan_rr *r);
49
50 bend_initresult *bend_init (bend_initrequest *q)
51 {
52     bend_initresult *r = (bend_initresult *)
53         odr_malloc (q->stream, sizeof(*r));
54     ZebraHandle zh;
55     struct statserv_options_block *sob;
56     char *user = NULL;
57     char *passwd = NULL;
58
59     r->errcode = 0;
60     r->errstring = 0;
61     q->bend_sort = bend_sort;
62     q->bend_delete = bend_delete;
63     q->bend_esrequest = bend_esrequest;
64     q->bend_segment = bend_segment;
65     q->bend_search = bend_search;
66     q->bend_fetch = bend_fetch;
67     q->bend_scan = bend_scan;
68
69     q->implementation_name = "Zebra Information Server";
70     q->implementation_version = "Zebra " ZEBRAVER;
71
72     logf (LOG_DEBUG, "bend_init");
73
74     sob = statserv_getcontrol ();
75     if (!(zh = zebra_open (sob->handle)))
76     {
77         yaz_log (LOG_FATAL, "Failed to open config `%s'", sob->configname);
78         r->errcode = 1;
79         return r;
80     }
81     if (q->auth)
82     {
83         if (q->auth->which == Z_IdAuthentication_open)
84         {
85             char *openpass = xstrdup (q->auth->u.open);
86             char *cp = strchr (openpass, '/');
87             if (cp)
88             {
89                 *cp = '\0';
90                 user = nmem_strdup (odr_getmem (q->stream), openpass);
91                 passwd = nmem_strdup (odr_getmem (q->stream), cp+1);
92             }
93             xfree (openpass);
94         }
95     }
96     if (zebra_auth (zh, user, passwd))
97     {
98         r->errcode = 222;
99         r->errstring = user;
100         zebra_close (zh);
101         return r;
102     }
103     r->handle = zh;
104     if (q->charneg_request) /* characater set and langauge negotiation? */
105     {
106         char **charsets = 0;
107         int num_charsets;
108         char **langs = 0;
109         int num_langs = 0;
110         int selected = 0;
111         int i;
112
113         NMEM nmem = nmem_create ();
114         yaz_log (LOG_LOG, "character set and language negotiation");
115
116         yaz_get_proposal_charneg (nmem, q->charneg_request,
117                                   &charsets, &num_charsets,
118                                   &langs, &num_langs, &selected);
119         for (i = 0; i < num_charsets; i++)
120         {
121             yaz_log (LOG_LOG, "charset %d %s", i, charsets[i]);
122             
123             if (odr_set_charset (q->decode, "UTF-8", charsets[i]) == 0)
124             {
125                 odr_set_charset (q->stream, charsets[i], "UTF-8");
126                 if (selected)
127                     zebra_record_encoding (zh, charsets[i]);
128                 q->charneg_response =
129                     yaz_set_response_charneg (q->stream, charsets[i],
130                                               0, selected);
131                 break;
132             }
133         }
134         nmem_destroy (nmem);
135     }
136     return r;
137 }
138
139 static void search_terms (ZebraHandle zh, bend_search_rr *r)
140 {
141     int count;
142     int no_terms;
143     int i;
144     int type;
145     struct Z_External *ext;
146     Z_SearchInfoReport *sr;
147
148     /* get no of terms for result set */
149     no_terms = zebra_resultSetTerms (zh, r->setname, 0, 0, 0, 0, 0);
150     if (!no_terms)
151         return;
152
153     r->search_info = odr_malloc (r->stream, sizeof(*r->search_info));
154
155     r->search_info->num_elements = 1;
156     r->search_info->list =
157         odr_malloc (r->stream, sizeof(*r->search_info->list));
158     r->search_info->list[0] =
159         odr_malloc (r->stream, sizeof(**r->search_info->list));
160     r->search_info->list[0]->category = 0;
161     r->search_info->list[0]->which = Z_OtherInfo_externallyDefinedInfo;
162     ext = odr_malloc (r->stream, sizeof(*ext));
163     r->search_info->list[0]->information.externallyDefinedInfo = ext;
164     ext->direct_reference =
165         yaz_oidval_to_z3950oid (r->stream, CLASS_USERINFO, VAL_SEARCHRES1);
166     ext->indirect_reference = 0;
167     ext->descriptor = 0;
168     ext->which = Z_External_searchResult1;
169     sr = odr_malloc (r->stream, sizeof(Z_SearchInfoReport));
170     ext->u.searchResult1 = sr;
171     sr->num = no_terms;
172     sr->elements = odr_malloc (r->stream, sr->num *
173                                sizeof(*sr->elements));
174     for (i = 0; i<no_terms; i++)
175     {
176         Z_Term *term;
177         char outbuf[1024];
178         size_t len = sizeof(outbuf);
179         zebra_resultSetTerms (zh, r->setname, i,
180                               &count, &type, outbuf, &len);
181         
182         sr->elements[i] = odr_malloc (r->stream, sizeof(**sr->elements));
183         sr->elements[i]->subqueryId = 0;
184         sr->elements[i]->fullQuery = odr_malloc (r->stream, 
185                                                  sizeof(bool_t));
186         *sr->elements[i]->fullQuery = 0;
187         sr->elements[i]->subqueryExpression = 
188             odr_malloc (r->stream, sizeof(Z_QueryExpression));
189         sr->elements[i]->subqueryExpression->which = 
190             Z_QueryExpression_term;
191         sr->elements[i]->subqueryExpression->u.term =
192             odr_malloc (r->stream, sizeof(Z_QueryExpressionTerm));
193         term = odr_malloc (r->stream, sizeof(Z_Term));
194         sr->elements[i]->subqueryExpression->u.term->queryTerm = term;
195         switch (type)
196         {
197         case Z_Term_characterString:
198             yaz_log (LOG_LOG, "term as characterString");
199             term->which = Z_Term_characterString;
200             term->u.characterString = odr_strdup (r->stream, outbuf);
201             break;
202         case Z_Term_general:
203             yaz_log (LOG_LOG, "term as general");
204             term->which = Z_Term_general;
205             term->u.general = odr_malloc (r->stream, sizeof(*term->u.general));
206             term->u.general->size = term->u.general->len = len;
207             term->u.general->buf = odr_malloc (r->stream, len);
208             memcpy (term->u.general->buf, outbuf, len);
209             break;
210         default:
211             term->which = Z_Term_general;
212             term->u.null = odr_nullval();
213         }
214         sr->elements[i]->subqueryExpression->u.term->termComment = 0;
215         sr->elements[i]->subqueryInterpretation = 0;
216         sr->elements[i]->subqueryRecommendation = 0;
217         sr->elements[i]->subqueryCount = odr_intdup (r->stream, count);
218         sr->elements[i]->subqueryWeight = 0;
219         sr->elements[i]->resultsByDB = 0;
220     }
221 }
222
223 int bend_search (void *handle, bend_search_rr *r)
224 {
225     ZebraHandle zh = (ZebraHandle) handle;
226
227     r->hits = 0;
228     r->errcode = 0;
229     r->errstring = NULL;
230     
231     if (zebra_select_databases (zh, r->num_bases,
232                                 (const char **) r->basenames))
233     {
234         zebra_result (zh, &r->errcode, &r->errstring);
235         return 0;
236     }
237     logf (LOG_LOG, "ResultSet '%s'", r->setname);
238     switch (r->query->which)
239     {
240     case Z_Query_type_1: case Z_Query_type_101:
241         zebra_search_rpn (zh, r->decode, r->stream, r->query->u.type_1,
242                           r->setname, &r->hits);
243         zebra_result (zh, &r->errcode, &r->errstring);
244         if (!r->errcode)
245             search_terms (zh, r);
246         break;
247     case Z_Query_type_2:
248         r->errcode = 107;
249         r->errstring = "type-2";
250         break;
251     default:
252         r->errcode = 107;
253     }
254     return 0;
255 }
256
257
258 int bend_fetch (void *handle, bend_fetch_rr *r)
259 {
260     ZebraHandle zh = (ZebraHandle) handle;
261     ZebraRetrievalRecord retrievalRecord;
262
263     retrievalRecord.position = r->number;
264     
265     r->last_in_set = 0;
266     zebra_records_retrieve (zh, r->stream, r->setname, r->comp,
267                             r->request_format, 1, &retrievalRecord);
268     zebra_result (zh, &r->errcode, &r->errstring);
269     /*  non Surrogate Diagnostic OR Surrogate Diagnostic */
270     if (r->errcode == 0 && retrievalRecord.errCode)
271     {
272         r->surrogate_flag = 1;
273         r->errcode = retrievalRecord.errCode;
274         r->errstring = retrievalRecord.errString;
275         r->basename = retrievalRecord.base;
276     }
277     else if (r->errcode == 0)        /* Database Record */
278     {
279         r->errcode = 0;
280         r->basename = retrievalRecord.base;
281         r->record = retrievalRecord.buf;
282         r->len = retrievalRecord.len;
283         r->output_format = retrievalRecord.format;
284     }
285     return 0;
286 }
287
288 static int bend_scan (void *handle, bend_scan_rr *r)
289 {
290     ZebraScanEntry *entries;
291     ZebraHandle zh = (ZebraHandle) handle;
292     int is_partial, i;
293
294     if (zebra_select_databases (zh, r->num_bases, 
295                                 (const char **) r->basenames))
296     {
297         zebra_result (zh, &r->errcode, &r->errstring);
298         return 0;
299     }
300     r->entries = (struct scan_entry *)
301         odr_malloc (r->stream, sizeof(*r->entries) * r->num_entries);
302     zebra_scan (zh, r->stream, r->term,
303                 r->attributeset,
304                 &r->term_position,
305                 &r->num_entries, &entries, &is_partial);
306     if (is_partial)
307         r->status = BEND_SCAN_PARTIAL;
308     else
309         r->status = BEND_SCAN_SUCCESS;
310     for (i = 0; i < r->num_entries; i++)
311     {
312         r->entries[i].term = entries[i].term;
313         r->entries[i].occurrences = entries[i].occurrences;
314     }
315     zebra_result (zh, &r->errcode, &r->errstring);
316     return 0;
317 }
318
319 void bend_close (void *handle)
320 {
321     zebra_close ((ZebraHandle) handle);
322     xmalloc_trav("bend_close");
323     nmem_print_list();
324 }
325
326 int bend_sort (void *handle, bend_sort_rr *rr)
327 {
328     ZebraHandle zh = (ZebraHandle) handle;
329
330     zebra_sort (zh, rr->stream,
331                 rr->num_input_setnames, (const char **) rr->input_setnames,
332                 rr->output_setname, rr->sort_sequence, &rr->sort_status);
333     zebra_result (zh, &rr->errcode, &rr->errstring);
334     return 0;
335 }
336
337 int bend_delete (void *handle, bend_delete_rr *rr)
338 {
339     ZebraHandle zh = (ZebraHandle) handle;
340
341     rr->delete_status = zebra_deleleResultSet(zh, rr->function,
342                                               rr->num_setnames, rr->setnames,
343                                               rr->statuses);
344     return 0;
345 }
346
347 static int es_admin_request (ZebraHandle zh, Z_AdminEsRequest *r)
348 {
349     switch (r->toKeep->which)
350     {
351     case Z_ESAdminOriginPartToKeep_reIndex:
352         yaz_log(LOG_LOG, "adm-reindex");
353         break;
354     case Z_ESAdminOriginPartToKeep_truncate:
355         yaz_log(LOG_LOG, "adm-truncate");
356         break;
357     case Z_ESAdminOriginPartToKeep_drop:
358         yaz_log(LOG_LOG, "adm-drop");
359         break;
360     case Z_ESAdminOriginPartToKeep_create:
361         yaz_log(LOG_LOG, "adm-create");
362         zebra_admin_create (zh, r->toKeep->databaseName);
363         break;
364     case Z_ESAdminOriginPartToKeep_import:
365         yaz_log(LOG_LOG, "adm-import");
366         zebra_admin_import_begin (zh, r->toKeep->databaseName);
367         break;
368     case Z_ESAdminOriginPartToKeep_refresh:
369         yaz_log(LOG_LOG, "adm-refresh");
370         break;
371     case Z_ESAdminOriginPartToKeep_commit:
372         yaz_log(LOG_LOG, "adm-commit");
373         break;
374     case Z_ESAdminOriginPartToKeep_shutdown:
375         yaz_log(LOG_LOG, "shutdown");
376         zebra_admin_shutdown(zh);
377         break;
378     case Z_ESAdminOriginPartToKeep_start:
379         yaz_log(LOG_LOG, "start");
380         zebra_admin_start(zh);
381         break;
382     default:
383         yaz_log(LOG_LOG, "unknown admin");
384     }
385     if (r->toKeep->databaseName)
386     {
387         yaz_log(LOG_LOG, "database %s", r->toKeep->databaseName);
388     }
389     return 0;
390 }
391
392 static int es_admin (ZebraHandle zh, Z_Admin *r)
393 {
394     switch (r->which)
395     {
396     case Z_Admin_esRequest:
397         es_admin_request (zh, r->u.esRequest);
398         break;
399     case Z_Admin_taskPackage:
400         yaz_log (LOG_LOG, "adm taskpackage (unhandled)");
401         break;
402     default:
403         break;
404     }
405
406     return 0;
407 }
408
409 int bend_segment (void *handle, bend_segment_rr *rr)
410 {
411     ZebraHandle zh = (ZebraHandle) handle;
412     Z_Segment *segment = rr->segment;
413
414     if (segment->num_segmentRecords)
415         zebra_admin_import_segment (zh, rr->segment);
416     else
417         zebra_admin_import_end (zh);
418     return 0;
419 }
420
421 int bend_esrequest (void *handle, bend_esrequest_rr *rr)
422 {
423     ZebraHandle zh = (ZebraHandle) handle;
424     
425     yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
426     if (rr->esr->packageName)
427         yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
428     yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
429
430     if (!rr->esr->taskSpecificParameters)
431     {
432         yaz_log (LOG_WARN, "No task specific parameters");
433     }
434     else if (rr->esr->taskSpecificParameters->which == Z_External_ESAdmin)
435     {
436         es_admin (zh, rr->esr->taskSpecificParameters->u.adminService);
437
438         zebra_result (zh, &rr->errcode, &rr->errstring);
439     }
440     else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
441     {
442         Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
443         yaz_log (LOG_LOG, "Received ItemOrder");
444         switch (it->which)
445         {
446 #ifdef ASN_COMPILED
447         case Z_IOItemOrder_esRequest:
448 #else
449         case Z_ItemOrder_esRequest:
450 #endif
451         {
452             Z_IORequest *ir = it->u.esRequest;
453             Z_IOOriginPartToKeep *k = ir->toKeep;
454             Z_IOOriginPartNotToKeep *n = ir->notToKeep;
455             
456             if (k && k->contact)
457             {
458                 if (k->contact->name)
459                     yaz_log(LOG_LOG, "contact name %s", k->contact->name);
460                 if (k->contact->phone)
461                     yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
462                 if (k->contact->email)
463                     yaz_log(LOG_LOG, "contact email %s", k->contact->email);
464             }
465             if (k->addlBilling)
466             {
467                 yaz_log(LOG_LOG, "Billing info (not shown)");
468             }
469             
470             if (n->resultSetItem)
471             {
472                 yaz_log(LOG_LOG, "resultsetItem");
473                 yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
474                 yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
475             }
476 #ifdef ASN_COMPILED
477             if (n->itemRequest)
478             {
479                 Z_External *r = (Z_External*) n->itemRequest;
480                 ILL_ItemRequest *item_req = 0;
481                 ILL_Request *ill_req = 0;
482                 if (r->direct_reference)
483                 {
484                     oident *ent = oid_getentbyoid(r->direct_reference);
485                     if (ent)
486                         yaz_log(LOG_LOG, "OID %s", ent->desc);
487                     if (ent && ent->value == VAL_ISO_ILL_1)
488                     {
489                         yaz_log (LOG_LOG, "ItemRequest");
490                         if (r->which == ODR_EXTERNAL_single)
491                         {
492                             odr_setbuf(rr->decode,
493                                        r->u.single_ASN1_type->buf,
494                                        r->u.single_ASN1_type->len, 0);
495                             
496                             if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
497                             {
498                                 yaz_log (LOG_LOG,
499                                     "Couldn't decode ItemRequest %s near %d",
500                                        odr_errmsg(odr_geterror(rr->decode)),
501                                        odr_offset(rr->decode));
502                                 yaz_log(LOG_LOG, "PDU dump:");
503                                 odr_dumpBER(yaz_log_file(),
504                                      r->u.single_ASN1_type->buf,
505                                      r->u.single_ASN1_type->len);
506                             }
507                             if (rr->print)
508                             {
509                                 ill_ItemRequest (rr->print, &item_req, 0,
510                                     "ItemRequest");
511                                 odr_reset (rr->print);
512                             }
513                         }
514                         if (!item_req && r->which == ODR_EXTERNAL_single)
515                         {
516                             yaz_log (LOG_LOG, "ILLRequest");
517                             odr_setbuf(rr->decode,
518                                        r->u.single_ASN1_type->buf,
519                                        r->u.single_ASN1_type->len, 0);
520                             
521                             if (!ill_Request (rr->decode, &ill_req, 0, 0))
522                             {
523                                 yaz_log (LOG_LOG,
524                                     "Couldn't decode ILLRequest %s near %d",
525                                        odr_errmsg(odr_geterror(rr->decode)),
526                                        odr_offset(rr->decode));
527                                 yaz_log(LOG_LOG, "PDU dump:");
528                                 odr_dumpBER(yaz_log_file(),
529                                      r->u.single_ASN1_type->buf,
530                                      r->u.single_ASN1_type->len);
531                             }
532                             if (rr->print)
533                             {
534                                 ill_Request (rr->print, &ill_req, 0,
535                                     "ILLRequest");
536                                 odr_reset (rr->print);
537                             }
538                         }
539                     }
540                 }
541                 if (item_req)
542                 {
543                     yaz_log (LOG_LOG, "ILL protocol version = %d",
544                              *item_req->protocol_version_num);
545                 }
546             }
547 #endif
548         }
549         break;
550         }
551     }
552     else if (rr->esr->taskSpecificParameters->which == Z_External_update)
553     {
554         Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
555         yaz_log (LOG_LOG, "Received DB Update");
556         if (up->which == Z_IUUpdate_esRequest)
557         {
558             Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
559             Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
560             Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
561             
562             yaz_log (LOG_LOG, "action");
563             if (toKeep->action)
564             {
565                 switch (*toKeep->action)
566                 {
567                 case Z_IUOriginPartToKeep_recordInsert:
568                     yaz_log (LOG_LOG, "recordInsert");
569                     break;
570                 case Z_IUOriginPartToKeep_recordReplace:
571                     yaz_log (LOG_LOG, "recordUpdate");
572                     break;
573                 case Z_IUOriginPartToKeep_recordDelete:
574                     yaz_log (LOG_LOG, "recordDelete");
575                     break;
576                 case Z_IUOriginPartToKeep_elementUpdate:
577                     yaz_log (LOG_LOG, "elementUpdate");
578                     break;
579                 case Z_IUOriginPartToKeep_specialUpdate:
580                     yaz_log (LOG_LOG, "specialUpdate");
581                     break;
582                 case Z_ESAdminOriginPartToKeep_shutdown:
583                     yaz_log (LOG_LOG, "shutDown");
584                     break;
585                 case Z_ESAdminOriginPartToKeep_start:
586                     yaz_log (LOG_LOG, "start");
587                     break;
588                 default:
589                     yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
590                 }
591             }
592             if (toKeep->databaseName)
593             {
594                 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
595                 if (!strcmp(toKeep->databaseName, "fault"))
596                 {
597                     rr->errcode = 109;
598                     rr->errstring = toKeep->databaseName;
599                 }
600                 if (!strcmp(toKeep->databaseName, "accept"))
601                     rr->errcode = -1;
602             }
603             if (notToKeep)
604             {
605                 int i;
606                 for (i = 0; i < notToKeep->num; i++)
607                 {
608                     Z_External *rec = notToKeep->elements[i]->record;
609
610                     if (rec->direct_reference)
611                     {
612                         struct oident *oident;
613                         oident = oid_getentbyoid(rec->direct_reference);
614                         if (oident)
615                             yaz_log (LOG_LOG, "record %d type %s", i,
616                                      oident->desc);
617                     }
618                     switch (rec->which)
619                     {
620                     case Z_External_sutrs:
621                         if (rec->u.octet_aligned->len > 170)
622                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
623                                      rec->u.sutrs->len,
624                                      rec->u.sutrs->buf);
625                         else
626                             yaz_log (LOG_LOG, "%d bytes:\n%s",
627                                      rec->u.sutrs->len,
628                                      rec->u.sutrs->buf);
629                         break;
630                     case Z_External_octet:
631                         if (rec->u.octet_aligned->len > 170)
632                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
633                                      rec->u.octet_aligned->len,
634                                      rec->u.octet_aligned->buf);
635                         else
636                             yaz_log (LOG_LOG, "%d bytes\n%s",
637                                      rec->u.octet_aligned->len,
638                                      rec->u.octet_aligned->buf);
639                     }
640                 }
641             }
642         }
643     }
644     else
645     {
646         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
647                  rr->esr->taskSpecificParameters->which);
648         
649     }
650     return 0;
651 }
652
653 static void bend_start (struct statserv_options_block *sob)
654 {
655 #ifdef WIN32
656     
657 #else
658     if (!sob->inetd) 
659     {
660         char *pidfile = "zebrasrv.pid";
661         int fd = creat (pidfile, 0666);
662         if (fd == -1)
663             logf (LOG_WARN|LOG_ERRNO, "creat %s", pidfile);
664         else
665         {
666             char pidstr[30];
667         
668             sprintf (pidstr, "%ld", (long) getpid ());
669             write (fd, pidstr, strlen(pidstr));
670             close (fd);
671         }
672     }
673 #endif
674     if (sob->handle)
675         zebra_stop((ZebraService) sob->handle);
676     sob->handle = zebra_start(sob->configname);
677 }
678
679 static void bend_stop(struct statserv_options_block *sob)
680 {
681 #ifdef WIN32
682
683 #else
684     if (!sob->inetd) 
685         unlink ("zebrasrv.pid");
686 #endif
687     if (sob->handle)
688     {
689         ZebraService service = sob->handle;
690         zebra_stop(service);
691     }
692 }
693
694 int main (int argc, char **argv)
695 {
696     struct statserv_options_block *sob;
697
698     sob = statserv_getcontrol ();
699     strcpy (sob->configname, "zebra.cfg");
700     sob->bend_start = bend_start;
701     sob->bend_stop = bend_stop;
702
703     statserv_setcontrol (sob);
704
705     return statserv_main (argc, argv, bend_init, bend_close);
706 }