Fix memory handling of quries in result sets
[idzebra-moved-to-github.git] / index / zserver.c
1 /* $Id: zserver.c,v 1.108 2003-06-18 11:46:33 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 #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         break;
386     case Z_ESAdminOriginPartToKeep_create:
387         yaz_log(LOG_LOG, "adm-create %s", r->toKeep->databaseName);
388         zebra_create_database (zh, r->toKeep->databaseName);
389         break;
390     case Z_ESAdminOriginPartToKeep_import:
391         yaz_log(LOG_LOG, "adm-import");
392         zebra_admin_import_begin (zh, r->toKeep->databaseName,
393                         r->toKeep->u.import->recordType);
394         break;
395     case Z_ESAdminOriginPartToKeep_refresh:
396         yaz_log(LOG_LOG, "adm-refresh");
397         break;
398     case Z_ESAdminOriginPartToKeep_commit:
399         yaz_log(LOG_LOG, "adm-commit");
400         break;
401     case Z_ESAdminOriginPartToKeep_shutdown:
402         yaz_log(LOG_LOG, "shutdown");
403         zebra_admin_shutdown(zh);
404         break;
405     case Z_ESAdminOriginPartToKeep_start:
406         yaz_log(LOG_LOG, "start");
407         zebra_admin_start(zh);
408         break;
409     default:
410         yaz_log(LOG_LOG, "unknown admin");
411     }
412     if (r->toKeep->databaseName)
413     {
414         yaz_log(LOG_LOG, "database %s", r->toKeep->databaseName);
415     }
416     return 0;
417 }
418
419 static int es_admin (ZebraHandle zh, Z_Admin *r)
420 {
421     switch (r->which)
422     {
423     case Z_Admin_esRequest:
424         es_admin_request (zh, r->u.esRequest);
425         break;
426     case Z_Admin_taskPackage:
427         yaz_log (LOG_LOG, "adm taskpackage (unhandled)");
428         break;
429     default:
430         break;
431     }
432
433     return 0;
434 }
435
436 int bend_segment (void *handle, bend_segment_rr *rr)
437 {
438     ZebraHandle zh = (ZebraHandle) handle;
439     Z_Segment *segment = rr->segment;
440
441     if (segment->num_segmentRecords)
442         zebra_admin_import_segment (zh, rr->segment);
443     else
444         zebra_admin_import_end (zh);
445     return 0;
446 }
447
448 int bend_esrequest (void *handle, bend_esrequest_rr *rr)
449 {
450     ZebraHandle zh = (ZebraHandle) handle;
451     
452     yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
453     if (rr->esr->packageName)
454         yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
455     yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
456
457     if (!rr->esr->taskSpecificParameters)
458     {
459         yaz_log (LOG_WARN, "No task specific parameters");
460     }
461     else if (rr->esr->taskSpecificParameters->which == Z_External_ESAdmin)
462     {
463         es_admin (zh, rr->esr->taskSpecificParameters->u.adminService);
464
465         zebra_result (zh, &rr->errcode, &rr->errstring);
466     }
467     else if (rr->esr->taskSpecificParameters->which == Z_External_update)
468     {
469         Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
470         yaz_log (LOG_LOG, "Received DB Update");
471         if (up->which == Z_IUUpdate_esRequest)
472         {
473             Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
474             Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
475             Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
476             
477             yaz_log (LOG_LOG, "action");
478             if (toKeep->action)
479             {
480                 switch (*toKeep->action)
481                 {
482                 case Z_IUOriginPartToKeep_recordInsert:
483                     yaz_log (LOG_LOG, "recordInsert");
484                     break;
485                 case Z_IUOriginPartToKeep_recordReplace:
486                     yaz_log (LOG_LOG, "recordUpdate");
487                     break;
488                 case Z_IUOriginPartToKeep_recordDelete:
489                     yaz_log (LOG_LOG, "recordDelete");
490                     break;
491                 case Z_IUOriginPartToKeep_elementUpdate:
492                     yaz_log (LOG_LOG, "elementUpdate");
493                     break;
494                 case Z_IUOriginPartToKeep_specialUpdate:
495                     yaz_log (LOG_LOG, "specialUpdate");
496                     break;
497                 case Z_ESAdminOriginPartToKeep_shutdown:
498                     yaz_log (LOG_LOG, "shutDown");
499                     break;
500                 case Z_ESAdminOriginPartToKeep_start:
501                     yaz_log (LOG_LOG, "start");
502                     break;
503                 default:
504                     yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
505                 }
506             }
507             if (toKeep->databaseName)
508             {
509                 yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
510
511                 if (zebra_select_database(zh, toKeep->databaseName))
512                     return 0;
513             }
514             else
515             {
516                 yaz_log (LOG_WARN, "no database supplied for ES Update");
517                 rr->errcode = 1008;
518                 rr->errstring = "database";
519                 return 0;
520             }
521             if (notToKeep)
522             {
523                 int i;
524                 zebra_begin_trans (zh, 1);
525                 for (i = 0; i < notToKeep->num; i++)
526                 {
527                     Z_External *rec = notToKeep->elements[i]->record;
528                     struct oident *oident = 0;
529                     Odr_oct *recid = notToKeep->elements[i]->u.opaque;
530
531                     if (!recid)
532                     {
533                         rr->errcode = 224;
534                         rr->errstring = "record Id not supplied";
535                         break;
536                     }
537                     if (notToKeep->elements[i]->which !=
538                         Z_IUSuppliedRecords_elem_opaque)
539                     {
540                         rr->errcode = 224;
541                         rr->errstring = "only opaque record ID supported";
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 = 1;
596
597                         if (!action)
598                         {
599                             rr->errcode = 224;
600                             rr->errstring = "unsupported ES Update action";
601                             break;
602                         }
603                         else
604                         {
605                             int r = zebra_admin_exchange_record (
606                                 zh, toKeep->databaseName,
607                                 rec->u.octet_aligned->buf,
608                                 rec->u.octet_aligned->len,
609                                 recid->buf, recid->len,
610                                 action);
611                             if (r && *toKeep->action ==
612                                 Z_IUOriginPartToKeep_specialUpdate)
613                             {
614                                 r = zebra_admin_exchange_record (
615                                     zh, toKeep->databaseName,
616                                     rec->u.octet_aligned->buf,
617                                     rec->u.octet_aligned->len,
618                                     recid->buf, recid->len,
619                                     2);
620                             }
621                             if (r)
622                             {
623                                 rr->errcode = 224;
624                                 rr->errstring = "record exchange failed";
625                                 break;
626                             }
627                         }
628                     }
629                 }
630                 zebra_end_trans (zh);
631             }
632         }
633     }
634     else
635     {
636         yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
637                  rr->esr->taskSpecificParameters->which);
638         rr->errcode = 221;
639         
640     }
641     return 0;
642 }
643
644 static void bend_start (struct statserv_options_block *sob)
645 {
646     if (sob->handle)
647         zebra_stop((ZebraService) sob->handle);
648     sob->handle = zebra_start(sob->configname);
649     if (!sob->handle)
650     {
651         yaz_log (LOG_FATAL, "Failed to read config `%s'", sob->configname);
652         exit (1);
653     }
654 #ifdef WIN32
655     
656 #else
657     if (!sob->inetd) 
658     {
659         struct flock area;
660         char *pidfile = "zebrasrv.pid";
661         int fd = open (pidfile, O_EXCL|O_WRONLY|O_CREAT, 0666);
662         if (fd == -1)
663         {
664             if (errno != EEXIST)
665             {
666                 yaz_log(LOG_FATAL|LOG_ERRNO, "lock file %s", pidfile);
667                 exit(1);
668             }
669             fd = open(pidfile, O_RDWR, 0666);
670             if (fd == -1)
671             {
672                 yaz_log(LOG_FATAL|LOG_ERRNO, "lock file %s", pidfile);
673                 exit(1);
674             }
675         }
676         area.l_type = F_WRLCK;
677         area.l_whence = SEEK_SET;
678         area.l_len = area.l_start = 0L;
679         if (fcntl (fd, F_SETLK, &area) == -1)
680         {
681             yaz_log(LOG_ERRNO|LOG_FATAL, "Zebra server already running");
682             exit(1);
683         }
684         else
685         {
686             char pidstr[30];
687         
688             sprintf (pidstr, "%ld", (long) getpid ());
689             write (fd, pidstr, strlen(pidstr));
690         }
691     }
692 #endif
693 }
694
695 static void bend_stop(struct statserv_options_block *sob)
696 {
697 #ifdef WIN32
698
699 #else
700     if (!sob->inetd) 
701         unlink ("zebrasrv.pid");
702 #endif
703     if (sob->handle)
704     {
705         ZebraService service = sob->handle;
706         zebra_stop(service);
707     }
708 }
709
710 int main (int argc, char **argv)
711 {
712     struct statserv_options_block *sob;
713
714     sob = statserv_getcontrol ();
715     strcpy (sob->configname, "zebra.cfg");
716     sob->bend_start = bend_start;
717     sob->bend_stop = bend_stop;
718 #ifdef WIN32
719     strcpy (sob->service_display_name, "Zebra Server");
720 #endif
721     statserv_setcontrol (sob);
722
723     return statserv_main (argc, argv, bend_init, bend_close);
724 }