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