Added check for fnmatch.h.
[yaz-moved-to-github.git] / client / admin.c
1 /*
2  * Copyright (c) 1995-2001, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: admin.c,v 1.12 2002-01-17 21:04:43 adam Exp $
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include <assert.h>
12
13 #if HAVE_FNMATCH_H
14 #include <dirent.h>
15 #include <fnmatch.h>
16 #include <sys/stat.h>
17 #endif
18
19 #include <yaz/yaz-util.h>
20
21 #include <yaz/tcpip.h>
22 #ifdef USE_XTIMOSI
23 #include <yaz/xmosi.h>
24 #endif
25
26 #include <yaz/proto.h>
27 #include <yaz/marcdisp.h>
28 #include <yaz/diagbib1.h>
29
30 #include <yaz/pquery.h>
31
32
33 /* Helper functions to get to various statics in the client */
34 ODR getODROutputStream();
35 void send_apdu(Z_APDU *a);
36
37 extern char *databaseNames[];
38 extern int num_databaseNames;
39
40 int sendAdminES(int type, char* param1)
41 {
42     ODR out = getODROutputStream();
43     char *dbname = odr_strdup (out, databaseNames[0]);
44
45     /* Type: 1=reindex, 2=truncate, 3=delete, 4=create, 5=import, 6=refresh, 7=commit */
46     Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
47     Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
48     Z_External *r;
49     int oid[OID_SIZE];
50     Z_ESAdminOriginPartToKeep  *toKeep;
51     Z_ESAdminOriginPartNotToKeep  *notToKeep;
52     oident update_oid;
53     printf ("Admin request\n");
54     fflush(stdout);
55
56     /* Set up the OID for the external */
57     update_oid.proto = PROTO_Z3950;
58     update_oid.oclass = CLASS_EXTSERV;
59     update_oid.value = VAL_ADMINSERVICE;
60
61     oid_ent_to_oid (&update_oid, oid);
62     req->packageType = odr_oiddup(out,oid);
63     req->packageName = "1.Extendedserveq";
64
65     /* Allocate the external */
66     r = req->taskSpecificParameters = (Z_External *) odr_malloc (out, sizeof(*r));
67     r->direct_reference = odr_oiddup(out,oid);
68     r->indirect_reference = 0;
69     r->descriptor = 0;
70     r->which = Z_External_ESAdmin;
71     r->u.adminService = (Z_Admin *) odr_malloc(out, sizeof(*r->u.adminService));
72     r->u.adminService->which = Z_Admin_esRequest;
73     r->u.adminService->u.esRequest = (Z_AdminEsRequest *) odr_malloc(out, sizeof(*r->u.adminService->u.esRequest));
74
75     toKeep = r->u.adminService->u.esRequest->toKeep = (Z_ESAdminOriginPartToKeep *) 
76                      odr_malloc(out, sizeof(*r->u.adminService->u.esRequest->toKeep));
77
78     toKeep->which=type;
79     toKeep->databaseName = dbname;
80     switch ( type )
81     {
82     case Z_ESAdminOriginPartToKeep_reIndex:
83         toKeep->u.reIndex=odr_nullval();
84         break;
85         
86     case Z_ESAdminOriginPartToKeep_truncate:
87         toKeep->u.truncate=odr_nullval();
88         break;
89     case Z_ESAdminOriginPartToKeep_drop:
90         toKeep->u.drop=odr_nullval();
91         break;
92     case Z_ESAdminOriginPartToKeep_create:
93         toKeep->u.create=odr_nullval();
94         break;
95     case Z_ESAdminOriginPartToKeep_import:
96         toKeep->u.import = (Z_ImportParameters*)odr_malloc(out, sizeof(*toKeep->u.import));
97         toKeep->u.import->recordType=param1;
98         /* Need to add additional setup of records here */
99         break;
100     case Z_ESAdminOriginPartToKeep_refresh:
101         toKeep->u.refresh=odr_nullval();
102         break;
103     case Z_ESAdminOriginPartToKeep_commit:
104         toKeep->u.commit=odr_nullval();
105         break;
106     case Z_ESAdminOriginPartToKeep_shutdown:
107         toKeep->u.commit=odr_nullval();
108         break;
109     case Z_ESAdminOriginPartToKeep_start:
110         toKeep->u.commit=odr_nullval();
111         break;
112     default:
113         /* Unknown admin service */
114         break;
115     }
116
117     notToKeep = r->u.adminService->u.esRequest->notToKeep =
118         (Z_ESAdminOriginPartNotToKeep *)
119         odr_malloc(out, sizeof(*r->u.adminService->u.esRequest->notToKeep));
120     notToKeep->which=Z_ESAdminOriginPartNotToKeep_recordsWillFollow;
121     notToKeep->u.recordsWillFollow=odr_nullval();
122     
123     send_apdu(apdu);
124     
125     return 0;
126 }
127
128 /* cmd_adm_reindex
129    Ask the specified database to fully reindex itself */
130 int cmd_adm_reindex(char* arg)
131 {
132     sendAdminES(Z_ESAdminOriginPartToKeep_reIndex, NULL);
133     return 2;
134 }
135
136 /* cmd_adm_truncate
137    Truncate the specified database, removing all records and index entries, but leaving 
138    the database & it's explain information intact ready for new records */
139 int cmd_adm_truncate(char* arg)
140 {
141     if ( arg )
142     {
143         sendAdminES(Z_ESAdminOriginPartToKeep_truncate, NULL);
144         return 2;
145     }
146     return 0;
147 }
148
149 /* cmd_adm_create
150    Create a new database */
151 int cmd_adm_create(char* arg)
152 {
153     if ( arg )
154     {
155         sendAdminES(Z_ESAdminOriginPartToKeep_create, NULL);
156         return 2;
157     }
158     return 0;
159 }
160
161 /* cmd_adm_drop
162    Drop (Delete) a database */
163 int cmd_adm_drop(char* arg)
164 {
165     if ( arg )
166     {
167         sendAdminES(Z_ESAdminOriginPartToKeep_drop, NULL);
168         return 2;
169     }
170     return 0;
171 }
172
173 /* cmd_adm_import <dbname> <rectype> <sourcefile>
174    Import the specified updated into the database
175    N.B. That in this case, the import may contain instructions to delete records as well as new or updates
176    to existing records */
177
178 #if HAVE_FNMATCH_H
179 int cmd_adm_import(char *arg)
180 {
181     char type_str[20], dir_str[1024], pattern_str[1024];
182     char *cp;
183     char *sep = "/";
184     DIR *dir;
185     struct dirent *ent;
186     int chunk = 10;
187     Z_APDU *apdu = 0;
188     Z_Segment *segment = 0;
189     ODR out = getODROutputStream();
190
191     if (arg && sscanf (arg, "%19s %1023s %1023s", type_str,
192                        dir_str, pattern_str) != 3)
193         return 0;
194     if (num_databaseNames != 1)
195         return 0;
196     dir = opendir(dir_str);
197     if (!dir)
198         return 0;
199     
200     sendAdminES(Z_ESAdminOriginPartToKeep_import, type_str);
201
202     printf ("sent es request\n");
203     if ((cp=strrchr(dir_str, '/')) && cp[1] == 0)
204         sep="";
205         
206     while ((ent = readdir(dir)))
207     {
208         if (fnmatch (pattern_str, ent->d_name, 0) == 0)
209         {
210             char fname[1024];
211             struct stat status;
212             FILE *inf;
213                 
214             sprintf (fname, "%s%s%s", dir_str, sep, ent->d_name);
215             stat (fname, &status);
216
217             if (S_ISREG(status.st_mode) && (inf = fopen(fname, "r")))
218             {
219                 Z_NamePlusRecord *rec;
220                 Odr_oct *oct = (Odr_oct *) odr_malloc (out, sizeof(*oct));
221
222                 if (!apdu)
223                 {
224                     apdu = zget_APDU(out, Z_APDU_segmentRequest);
225                     segment = apdu->u.segmentRequest;
226                     segment->segmentRecords = (Z_NamePlusRecord **)
227                         odr_malloc (out, chunk * sizeof(*segment->segmentRecords));
228                 }
229                 rec = (Z_NamePlusRecord *) odr_malloc (out, sizeof(*rec));
230                 rec->databaseName = 0;
231                 rec->which = Z_NamePlusRecord_intermediateFragment;
232                 rec->u.intermediateFragment = (Z_FragmentSyntax *)
233                     odr_malloc (out, sizeof(*rec->u.intermediateFragment));
234                 rec->u.intermediateFragment->which =
235                     Z_FragmentSyntax_notExternallyTagged;
236                 rec->u.intermediateFragment->u.notExternallyTagged = oct;
237                 
238                 oct->len = oct->size = status.st_size;
239                 oct->buf = (unsigned char *) odr_malloc (out, oct->size);
240                 fread (oct->buf, 1, oct->size, inf);
241                 fclose (inf);
242                 
243                 segment->segmentRecords[segment->num_segmentRecords++] = rec;
244
245                 if (segment->num_segmentRecords == chunk)
246                 {
247                     send_apdu (apdu);
248                     apdu = 0;
249                 }
250             }   
251         }
252     }
253     if (apdu)
254         send_apdu(apdu);
255     apdu = zget_APDU(out, Z_APDU_segmentRequest);
256     send_apdu (apdu);
257     closedir(dir);
258     return 2;
259 }
260 #else
261 int cmd_adm_import(char *arg)
262 {
263     printf ("not available on WIN32\n");
264     return 0;
265 }
266 #endif
267
268 int cmd_adm_import2(char* arg)
269 {
270    /* Buffer for reading chunks of data from import file */
271     char chunk_buffer[8192];
272     
273     if ( arg )
274     {
275         char rectype_buff[32];
276         char filename_buff[32];
277         FILE* pImportFile = NULL;
278
279         if (sscanf (arg, "%s %s", rectype_buff, filename_buff) != 3)
280         {
281             printf("Must specify database-name, record-type and filename for import\n");
282             return 0;
283         }
284
285         /* Attempt to open the file */
286
287         pImportFile = fopen(filename_buff,"r");
288
289         /* This chunk of code should move into client.c sometime soon for sending files via the update es */
290         /* This function will then refer to the standard client.c one for uploading a file using es update */
291         if ( pImportFile )
292         {
293             int iTotalWritten = 0;
294
295             /* We opened the import file without problems... So no we send the es request, ready to 
296                start sending fragments of the import file as segment messages */
297             sendAdminES(Z_ESAdminOriginPartToKeep_import, rectype_buff);
298
299             while ( ! feof(pImportFile ) )
300             {
301                 /* Read buffer_size bytes from the file */
302                 size_t num_items = fread((void*)chunk_buffer, 1, sizeof(chunk_buffer),  pImportFile);
303
304                 /* Write num_bytes of data to */
305
306                 if ( feof(pImportFile ) )
307                 {
308                     /* This is the last chunk... Write it as the last fragment */
309                     printf("Last segment of %d bytes\n", num_items);
310                 }
311                 else if ( iTotalWritten == 0 )
312                 {
313                     printf("First segment of %d bytes\n",num_items);
314                 }
315                 else
316                 {
317                     printf("Writing %d bytes\n", num_items);
318                 }
319
320                 iTotalWritten += num_items;
321             }
322         }
323         return 2;
324     }
325     return 0;
326 }
327
328 /* "Freshen" the specified database, by checking metadata records against the sources from which they were 
329    generated, and creating a new record if the source has been touched since the last extraction */
330 int cmd_adm_refresh(char* arg)
331 {
332     if ( arg )
333     {
334         sendAdminES(Z_ESAdminOriginPartToKeep_refresh, NULL);
335         return 2;
336     }
337     return 0;
338 }
339
340 /* cmd_adm_commit 
341    Make imported records a permenant & visible to the live system */
342 int cmd_adm_commit(char* arg)
343 {
344     sendAdminES(Z_ESAdminOriginPartToKeep_commit, NULL);
345     return 2;
346 }
347
348 int cmd_adm_shutdown(char* arg)
349 {
350     sendAdminES(Z_ESAdminOriginPartToKeep_shutdown, NULL);
351     return 2;
352 }
353
354 int cmd_adm_startup(char* arg)
355 {
356     sendAdminES(Z_ESAdminOriginPartToKeep_start, NULL);
357     return 2;
358 }