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