Remote drop of database
[idzebra-moved-to-github.git] / index / zserver.c
1 /* $Id: zserver.c,v 1.109 2003-07-02 22:00:06 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003
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, right_name,
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 *recid = notToKeep->elements[i]->u.opaque;
531
532                     if (!recid)
533                     {
534                         rr->errcode = 224;
535                         rr->errstring = "record Id not supplied";
536                         break;
537                     }
538                     if (notToKeep->elements[i]->which !=
539                         Z_IUSuppliedRecords_elem_opaque)
540                     {
541                         rr->errcode = 224;
542                         rr->errstring = "only opaque record ID supported";
543                         break;
544                     }
545                         
546                     if (rec->direct_reference)
547                     {
548                         oident = oid_getentbyoid(rec->direct_reference);
549                         if (oident)
550                             yaz_log (LOG_LOG, "record %d type %s", i,
551                                      oident->desc);
552                     }
553                     switch (rec->which)
554                     {
555                     case Z_External_sutrs:
556                         if (rec->u.octet_aligned->len > 170)
557                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
558                                      rec->u.sutrs->len,
559                                      rec->u.sutrs->buf);
560                         else
561                             yaz_log (LOG_LOG, "%d bytes:\n%s",
562                                      rec->u.sutrs->len,
563                                      rec->u.sutrs->buf);
564                         break;
565                     case Z_External_octet:
566                         if (rec->u.octet_aligned->len > 170)
567                             yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
568                                      rec->u.octet_aligned->len,
569                                      rec->u.octet_aligned->buf);
570                         else
571                             yaz_log (LOG_LOG, "%d bytes\n%s",
572                                      rec->u.octet_aligned->len,
573                                      rec->u.octet_aligned->buf);
574                     }
575                     if (oident && oident->value != VAL_TEXT_XML)
576                     {
577                         rr->errcode = 224;
578                         rr->errstring = "only XML update supported";
579                         break;
580                     }
581                     if (rec->which == Z_External_octet)
582                     {
583                         int action = 0;
584
585                         if (*toKeep->action ==
586                             Z_IUOriginPartToKeep_recordInsert)
587                             action = 1;
588                         if (*toKeep->action ==
589                             Z_IUOriginPartToKeep_recordReplace)
590                             action = 2;
591                         if (*toKeep->action ==
592                             Z_IUOriginPartToKeep_recordDelete)
593                             action = 3;
594                         if (*toKeep->action ==
595                             Z_IUOriginPartToKeep_specialUpdate)
596                             action = 1;
597
598                         if (!action)
599                         {
600                             rr->errcode = 224;
601                             rr->errstring = "unsupported ES Update action";
602                             break;
603                         }
604                         else
605                         {
606                             int r = zebra_admin_exchange_record (
607                                 zh, toKeep->databaseName,
608                                 rec->u.octet_aligned->buf,
609                                 rec->u.octet_aligned->len,
610                                 recid->buf, recid->len,
611                                 action);
612                             if (r && *toKeep->action ==
613                                 Z_IUOriginPartToKeep_specialUpdate)
614                             {
615                                 r = zebra_admin_exchange_record (
616                                     zh, toKeep->databaseName,
617                                     rec->u.octet_aligned->buf,
618                                     rec->u.octet_aligned->len,
619                                     recid->buf, recid->len,
620                                     2);
621                             }
622                             if (r)
623                             {
624                                 rr->errcode = 224;
625                                 rr->errstring = "record exchange failed";
626                                 break;
627                             }
628                         }
629                     }
630                 }
631                 zebra_end_trans (zh);
632             }
633         }
634     }
635     else
636     {
637         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
638                  rr->esr->taskSpecificParameters->which);
639         rr->errcode = 221;
640         
641     }
642     return 0;
643 }
644
645 static void bend_start (struct statserv_options_block *sob)
646 {
647     if (sob->handle)
648         zebra_stop((ZebraService) sob->handle);
649     sob->handle = zebra_start(sob->configname);
650     if (!sob->handle)
651     {
652         yaz_log (LOG_FATAL, "Failed to read config `%s'", sob->configname);
653         exit (1);
654     }
655 #ifdef WIN32
656     
657 #else
658     if (!sob->inetd) 
659     {
660         struct flock area;
661         char *pidfile = "zebrasrv.pid";
662         int fd = open (pidfile, O_EXCL|O_WRONLY|O_CREAT, 0666);
663         if (fd == -1)
664         {
665             if (errno != EEXIST)
666             {
667                 yaz_log(LOG_FATAL|LOG_ERRNO, "lock file %s", pidfile);
668                 exit(1);
669             }
670             fd = open(pidfile, O_RDWR, 0666);
671             if (fd == -1)
672             {
673                 yaz_log(LOG_FATAL|LOG_ERRNO, "lock file %s", pidfile);
674                 exit(1);
675             }
676         }
677         area.l_type = F_WRLCK;
678         area.l_whence = SEEK_SET;
679         area.l_len = area.l_start = 0L;
680         if (fcntl (fd, F_SETLK, &area) == -1)
681         {
682             yaz_log(LOG_ERRNO|LOG_FATAL, "Zebra server already running");
683             exit(1);
684         }
685         else
686         {
687             char pidstr[30];
688         
689             sprintf (pidstr, "%ld", (long) getpid ());
690             write (fd, pidstr, strlen(pidstr));
691         }
692     }
693 #endif
694 }
695
696 static void bend_stop(struct statserv_options_block *sob)
697 {
698 #ifdef WIN32
699
700 #else
701     if (!sob->inetd) 
702         unlink ("zebrasrv.pid");
703 #endif
704     if (sob->handle)
705     {
706         ZebraService service = sob->handle;
707         zebra_stop(service);
708     }
709 }
710
711 int main (int argc, char **argv)
712 {
713     struct statserv_options_block *sob;
714
715     sob = statserv_getcontrol ();
716     strcpy (sob->configname, "zebra.cfg");
717     sob->bend_start = bend_start;
718     sob->bend_stop = bend_stop;
719 #ifdef WIN32
720     strcpy (sob->service_display_name, "Zebra Server");
721 #endif
722     statserv_setcontrol (sob);
723
724     return statserv_main (argc, argv, bend_init, bend_close);
725 }