Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / apps / gdp-reader.c @ master

History | View | Annotate | Download (16.7 KB)

1 a901db09 Eric Allman
/* vim: set ai sw=4 sts=4 ts=4 : */
2 47c6ea64 Eric Allman
3 97696c1c Eric Allman
/*
4 8baa1d3b Eric Allman
**  GDP-READER --- read and print records from a GDP log
5 97696c1c Eric Allman
**
6 daa7dbce Eric Allman
**                Unfortunately it isn't that simple, since it is possible to read
7
**                using all the internal mechanisms.  The -c, -m, and -s flags
8
**                control which approach is being used.
9
**
10 97696c1c Eric Allman
**                There are two ways of reading.  The first is to get individual
11 daa7dbce Eric Allman
**                records in a loop (as implemented in do_simpleread), and the
12
**                second is to request a batch of records (as implemented in
13 8baa1d3b Eric Allman
**                do_async_read or do_subscribe); these are returned as events
14
**                that are collected after the initial command completes or as
15
**                callbacks that are invoked in a separate thread.  There are two
16
**                interfaces for the event/callback techniques; one only reads
17
**                existing data, and the other ("subscriptions") will wait for
18
**                data to be appended by another client.
19 055d3009 Eric Allman
**
20
**        ----- BEGIN LICENSE BLOCK -----
21
**        Applications for the Global Data Plane
22
**        From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
23
**
24 c87dd166 Eric Allman
**        Copyright (c) 2015-2019, Regents of the University of California.
25 6bd5476b Eric Allman
**        All rights reserved.
26 055d3009 Eric Allman
**
27 6bd5476b Eric Allman
**        Permission is hereby granted, without written agreement and without
28
**        license or royalty fees, to use, copy, modify, and distribute this
29
**        software and its documentation for any purpose, provided that the above
30
**        copyright notice and the following two paragraphs appear in all copies
31
**        of this software.
32 055d3009 Eric Allman
**
33 6bd5476b Eric Allman
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
34
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
35
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
36
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 055d3009 Eric Allman
**
38 6bd5476b Eric Allman
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
39 055d3009 Eric Allman
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
40 6bd5476b Eric Allman
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
41
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
42
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
43
**        OR MODIFICATIONS.
44 055d3009 Eric Allman
**        ----- END LICENSE BLOCK -----
45 97696c1c Eric Allman
*/
46
47 055d3009 Eric Allman
#include <ep/ep.h>
48
#include <ep/ep_dbg.h>
49
#include <ep/ep_app.h>
50
#include <ep/ep_time.h>
51
#include <gdp/gdp.h>
52
#include <event2/buffer.h>
53
54
#include <unistd.h>
55
#include <errno.h>
56
#include <errno.h>
57
#include <getopt.h>
58
#include <string.h>
59
#include <sysexits.h>
60
61 6e2cccae Eric Allman
static EP_DBG        Dbg = EP_DBG_INIT("gdp-reader", "GDP Reader Application");
62 a2cf45db Eric Allman
63 65309098 Eric Allman
#ifndef USE_GETDATE
64
# define USE_GETDATE                1
65
#endif
66
67 97696c1c Eric Allman
68
/*
69 fd6e357c Eric Allman
**  DO_LOG --- log a timestamp (for performance checking).
70
*/
71
72
FILE        *LogFile;
73 b42c4583 Eric Allman
bool        TextData = false;                // set if data should be displayed as text
74 c3369218 Eric Allman
bool        BinaryData = false;                // set if data should be output as binary
75 c8e97446 Eric Allman
bool        PrintSig = false;                // set if signature should be printed
76 87a0bdac Eric Allman
bool        Quiet = false;                        // don't print metadata
77 e919422a Eric Allman
int                NRead = 0;                                // number of datums read
78 2318b019 Eric Allman
FILE        *OutFile;                                // data output file
79 fd6e357c Eric Allman
80
void
81
do_log(const char *tag)
82
{
83
        struct timeval tv;
84
85
        if (LogFile == NULL)
86
                return;
87
        gettimeofday(&tv, NULL);
88
        fprintf(LogFile, "%s %ld.%06ld\n", tag, tv.tv_sec, (long) tv.tv_usec);
89
}
90
91
#define LOG(tag)        { if (LogFile != NULL) do_log(tag); }
92
93 b42c4583 Eric Allman
/*
94
**  PRINTDATUM --- just print out a datum
95
*/
96
97
void
98
printdatum(gdp_datum_t *datum, FILE *fp)
99
{
100 c8e97446 Eric Allman
        uint32_t prflags = 0;
101
102 65309098 Eric Allman
        // logging for simple performance testing
103
        LOG("R");
104
105 c8e97446 Eric Allman
        if (TextData)
106
                prflags |= GDP_DATUM_PRTEXT;
107 c3369218 Eric Allman
        if (BinaryData)
108
                prflags |= GDP_DATUM_PRBINARY;
109 c8e97446 Eric Allman
        if (PrintSig)
110
                prflags |= GDP_DATUM_PRSIG;
111 87a0bdac Eric Allman
        if (Quiet)
112
                prflags |= GDP_DATUM_PRQUIET;
113 b42c4583 Eric Allman
        flockfile(fp);
114 87a0bdac Eric Allman
        if (!Quiet)
115
                fprintf(fp, " >>> ");
116 c8e97446 Eric Allman
        gdp_datum_print(datum, fp, prflags);
117 b42c4583 Eric Allman
        funlockfile(fp);
118 e919422a Eric Allman
        NRead++;
119 b42c4583 Eric Allman
}
120
121 fd6e357c Eric Allman
122
/*
123 8baa1d3b Eric Allman
**  DO_SIMPLEREAD --- read from a log using the one-record-at-a-time call
124 97696c1c Eric Allman
*/
125
126 9509f13b Eric Allman
EP_STAT
127 eae1d3ec Eric Allman
do_simpleread(gdp_gin_t *gin,
128 65309098 Eric Allman
                gdp_recno_t firstrec,
129
                const char *dtstr,
130
                int numrecs)
131 9509f13b Eric Allman
{
132 723cc82b Eric Allman
        EP_STAT estat = EP_STAT_OK;
133 2e65953f Eric Allman
        gdp_datum_t *datum = gdp_datum_new();
134 9509f13b Eric Allman
135 97696c1c Eric Allman
        // change the "infinity" sentinel to make the loop easier
136 552b93fd Eric Allman
        if (numrecs == 0)
137
                numrecs = -1;
138 97696c1c Eric Allman
139 9e8a5f86 Eric Allman
        // can't start reading before first record (but negative makes sense)
140
        if (firstrec == 0)
141
                firstrec = 1;
142
143 65309098 Eric Allman
        // are we reading by record number or by timestamp?
144
        if (dtstr == NULL)
145 9509f13b Eric Allman
        {
146 65309098 Eric Allman
                // record number
147 eae1d3ec Eric Allman
                estat = gdp_gin_read_by_recno(gin, firstrec, datum);
148 65309098 Eric Allman
        }
149
        else
150
        {
151
                // timestamp
152
                EP_TIME_SPEC ts;
153 97696c1c Eric Allman
154 d2647d1f Eric Allman
                estat = ep_time_parse(dtstr, &ts, EP_TIME_USE_LOCALTIME);
155 65309098 Eric Allman
                if (!EP_STAT_ISOK(estat))
156
                {
157 a0217621 Eric Allman
                        ep_app_message(estat,
158
                                                "Cannot convert date/time string \"%s\"",
159
                                                dtstr);
160 65309098 Eric Allman
                        goto done;
161
                }
162 97696c1c Eric Allman
163 eae1d3ec Eric Allman
                estat = gdp_gin_read_by_ts(gin, &ts, datum);
164 65309098 Eric Allman
        }
165 97696c1c Eric Allman
166 65309098 Eric Allman
        // start reading data, one record at a time
167
        while (EP_STAT_ISOK(estat) && (numrecs < 0 || --numrecs > 0))
168
        {
169
                gdp_recno_t recno;
170
171
                // print the previous value
172 2318b019 Eric Allman
                printdatum(datum, OutFile);
173 9509f13b Eric Allman
174
                // flush any left over data
175 7fc131d1 Eric Allman
                if (gdp_buf_reset(gdp_datum_getbuf(datum)) < 0)
176 5bc1cdfb Eric Allman
                {
177
                        char nbuf[40];
178
179 bfecf573 Eric Allman
                        (void) (0 == strerror_r(errno, nbuf, sizeof nbuf));
180 a0217621 Eric Allman
                        ep_app_warn("buffer reset failed: %s", nbuf);
181 5bc1cdfb Eric Allman
                }
182 65309098 Eric Allman
183
                // move to next record
184
                recno = gdp_datum_getrecno(datum) + 1;
185 eae1d3ec Eric Allman
                estat = gdp_gin_read_by_recno(gin, recno, datum);
186 8204d4b2 Eric Allman
        }
187 65309098 Eric Allman
188
        // print the final value
189
        if (EP_STAT_ISOK(estat))
190 2318b019 Eric Allman
                printdatum(datum, OutFile);
191 8ec0d882 Eric Allman
192 97696c1c Eric Allman
        // end of data is returned as a "not found" error: turn it into a warning
193
        //    to avoid scaring the unsuspecting user
194 d21d615a Eric Allman
        if (EP_STAT_IS_SAME(estat, GDP_STAT_NAK_NOTFOUND))
195 8ec0d882 Eric Allman
                estat = EP_STAT_END_OF_FILE;
196 65309098 Eric Allman
197
done:
198
        gdp_datum_free(datum);
199 9509f13b Eric Allman
        return estat;
200
}
201
202
203 8204d4b2 Eric Allman
/*
204 8baa1d3b Eric Allman
**  Async Read and Subscriptions.
205 8204d4b2 Eric Allman
*/
206
207 fe034bdb Eric Allman
EP_STAT
208 8baa1d3b Eric Allman
print_event(gdp_event_t *gev)
209 fe034bdb Eric Allman
{
210 8204d4b2 Eric Allman
        EP_STAT estat = gdp_event_getstat(gev);
211 8baa1d3b Eric Allman
        const char *op = gdp_event_getudata(gev);
212
213
        if (op == NULL)
214
                op = "Unknown";
215 8204d4b2 Eric Allman
216 fe034bdb Eric Allman
        // decode it
217
        switch (gdp_event_gettype(gev))
218
        {
219
          case GDP_EVENT_DATA:
220
                // this event contains a data return
221 fd6e357c Eric Allman
                LOG("S");
222 2318b019 Eric Allman
                printdatum(gdp_event_getdatum(gev), OutFile);
223 fe034bdb Eric Allman
                break;
224
225 5ced6d34 Eric Allman
          case GDP_EVENT_DONE:
226 fe034bdb Eric Allman
                // "end of subscription": no more data will be returned
227 b201e69b Eric Allman
                if (!Quiet)
228
                {
229 8baa1d3b Eric Allman
                        ep_app_info("End of %s", op);
230 b201e69b Eric Allman
                }
231 8204d4b2 Eric Allman
                estat = EP_STAT_END_OF_FILE;
232
                break;
233 fe034bdb Eric Allman
234 cf71c5ea Eric Allman
          case GDP_EVENT_SHUTDOWN:
235
                // log daemon has shut down, meaning we lose our subscription
236 8204d4b2 Eric Allman
                estat = GDP_STAT_DEAD_DAEMON;
237 8baa1d3b Eric Allman
                ep_app_message(estat, "%s terminating because of log daemon shutdown", op);
238 8204d4b2 Eric Allman
                break;
239
240
          case GDP_EVENT_CREATED:
241 a0217621 Eric Allman
                ep_app_info("Successful append, create, or similar");
242 8204d4b2 Eric Allman
                break;
243
244 fe034bdb Eric Allman
          default:
245 6f52b2b7 Eric Allman
                // let the library handle this
246 ada5f328 Eric Allman
                gdp_event_print(gev, stderr);
247 fe034bdb Eric Allman
                break;
248
        }
249
250 b201e69b Eric Allman
        if (EP_STAT_ISFAIL(estat))                        // ERROR or higher severity
251 8204d4b2 Eric Allman
        {
252
                char ebuf[100];
253
                fprintf(stderr, "    STATUS: %s\n",
254
                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
255
        }
256
        return estat;
257 fe034bdb Eric Allman
}
258
259
260
void
261 8baa1d3b Eric Allman
read_cb(gdp_event_t *gev)
262 fe034bdb Eric Allman
{
263 8baa1d3b Eric Allman
        (void) print_event(gev);
264 fe034bdb Eric Allman
        gdp_event_free(gev);
265
}
266
267
268 328d0948 Eric Allman
/*
269 8baa1d3b Eric Allman
**  DO_SUBSCRIBE --- subscribe to a log, possibly using callbacks
270 328d0948 Eric Allman
**
271
**                This routine handles calls that return multiple values via the
272
**                event interface.  They might include subscriptions.
273
*/
274
275 9509f13b Eric Allman
EP_STAT
276 8baa1d3b Eric Allman
do_subscribe(gdp_gin_t *gin,
277 fe034bdb Eric Allman
                gdp_recno_t firstrec,
278 d2647d1f Eric Allman
                const char *dtstr,
279 fe034bdb Eric Allman
                int32_t numrecs,
280
                bool use_callbacks)
281 9509f13b Eric Allman
{
282
        EP_STAT estat;
283 fe034bdb Eric Allman
        void (*cbfunc)(gdp_event_t *) = NULL;
284 d2647d1f Eric Allman
        EP_TIME_SPEC ts;
285 fe034bdb Eric Allman
286
        if (use_callbacks)
287 8baa1d3b Eric Allman
                cbfunc = read_cb;
288 9509f13b Eric Allman
289 d2647d1f Eric Allman
        // are we reading by record number or by timestamp?
290
        if (dtstr != NULL)
291
        {
292
                // timestamp
293
                estat = ep_time_parse(dtstr, &ts, EP_TIME_USE_LOCALTIME);
294
                if (!EP_STAT_ISOK(estat))
295
                {
296 9829d4ae Eric Allman
                        ep_app_message(estat, "Cannot convert date/time string \"%s\"",
297
                                                dtstr);
298 d2647d1f Eric Allman
                        return estat;
299
                }
300
        }
301
302 8baa1d3b Eric Allman
        // start up a subscription
303
        if (dtstr == NULL)
304
                estat = gdp_gin_subscribe_by_recno(gin, firstrec, numrecs,
305
                                                                NULL, cbfunc, "Subscription");
306 328d0948 Eric Allman
        else
307 8baa1d3b Eric Allman
                estat = gdp_gin_subscribe_by_ts(gin, &ts, numrecs,
308
                                                                NULL, cbfunc, "Subscription");
309 328d0948 Eric Allman
310 8baa1d3b Eric Allman
        // check to make sure the subscribe succeeded; if not, bail
311 9509f13b Eric Allman
        if (!EP_STAT_ISOK(estat))
312
        {
313
                char ebuf[200];
314
315 8baa1d3b Eric Allman
                ep_app_fatal("Cannot subscribe: %s",
316 9509f13b Eric Allman
                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
317
        }
318
319 066f1491 Eric Allman
        // this sleep will allow multiple results to appear before we start reading
320 ec2466b6 Eric Allman
        if (ep_dbg_test(Dbg, 100))
321 a2cf45db Eric Allman
                ep_time_nanosleep(500000000);        //DEBUG: one half second
322 066f1491 Eric Allman
323 97696c1c Eric Allman
        // now start reading the events that will be generated
324 fe034bdb Eric Allman
        if (!use_callbacks)
325 9509f13b Eric Allman
        {
326 328ab6a8 Eric Allman
                int32_t ndone = 0;
327 fe034bdb Eric Allman
                for (;;)
328 9509f13b Eric Allman
                {
329 0aa58d96 Eric Allman
                        // for testing: force early termination and close
330
                        if (ep_dbg_test(Dbg, 127) && ++ndone >= numrecs)
331
                                break;
332
333 fe034bdb Eric Allman
                        // get the next incoming event
334 55b8c1ad Eric Allman
                        gdp_event_t *gev = gdp_event_next(NULL, 0);
335 9509f13b Eric Allman
336 fe034bdb Eric Allman
                        // print it
337 8baa1d3b Eric Allman
                        estat = print_event(gev);
338 2e4a5d7d Eric Allman
339 fe034bdb Eric Allman
                        // don't forget to free the event!
340
                        gdp_event_free(gev);
341 97696c1c Eric Allman
342 fe034bdb Eric Allman
                        EP_STAT_CHECK(estat, break);
343 9509f13b Eric Allman
                }
344 fe034bdb Eric Allman
        }
345
        else
346
        {
347
                // hang for an hour waiting for events
348
                sleep(3600);
349 9509f13b Eric Allman
        }
350 a1a8f4f7 Eric Allman
351 9509f13b Eric Allman
        return estat;
352
}
353
354 47c6ea64 Eric Allman
355 97696c1c Eric Allman
/*
356 8204d4b2 Eric Allman
**  DO_ASYNC_READ --- read asynchronously
357
*/
358
359
EP_STAT
360 eae1d3ec Eric Allman
do_async_read(gdp_gin_t *gin,
361 8204d4b2 Eric Allman
                gdp_recno_t firstrec,
362
                int32_t numrecs,
363
                bool use_callbacks)
364
{
365
        EP_STAT estat = EP_STAT_OK;
366
        gdp_event_cbfunc_t cbfunc = NULL;
367
368
        if (use_callbacks)
369 8baa1d3b Eric Allman
                cbfunc = read_cb;
370 8204d4b2 Eric Allman
371
        // make the flags more user-friendly
372
        if (firstrec == 0)
373
                firstrec = 1;
374
        if (numrecs <= 0)
375 eae1d3ec Eric Allman
                numrecs = gdp_gin_getnrecs(gin);
376 5ae1898b Eric Allman
        if (firstrec < 0)
377
        {
378 93e43d6b Eric Allman
                firstrec += numrecs + 1;
379
                numrecs -= firstrec - 1;
380 5ae1898b Eric Allman
        }
381 8204d4b2 Eric Allman
382 8baa1d3b Eric Allman
        // issue the async read command without reading results yet
383
        estat = gdp_gin_read_by_recno_async(gin, firstrec, numrecs,
384
                                                        cbfunc, "Async Read");
385 fdeae6ab Eric Allman
        if (!EP_STAT_ISOK(estat))
386 8204d4b2 Eric Allman
        {
387 fdeae6ab Eric Allman
                char ebuf[100];
388
                ep_app_error("async_read: gdp_gin_read_by_recno_async error:\n\t%s",
389
                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
390 8204d4b2 Eric Allman
        }
391
392
        // this sleep will allow multiple results to appear before we start reading
393
        if (ep_dbg_test(Dbg, 100))
394
                ep_time_nanosleep(500000000);        //DEBUG: one half second
395
396
        // now start reading the events that will be generated
397
        if (!use_callbacks)
398
        {
399 fdeae6ab Eric Allman
                do
400 8204d4b2 Eric Allman
                {
401
                        // get the next incoming event
402
                        gdp_event_t *gev = gdp_event_next(NULL, 0);
403
404
                        // print it
405 8baa1d3b Eric Allman
                        estat = print_event(gev);
406 8204d4b2 Eric Allman
407
                        // don't forget to free the event!
408
                        gdp_event_free(gev);
409
410
                        //EP_STAT_CHECK(estat, break);
411 fdeae6ab Eric Allman
                } while (EP_STAT_ISOK(estat));
412 8204d4b2 Eric Allman
        }
413
        else
414
        {
415 8baa1d3b Eric Allman
                // hang for 60 seconds waiting for events
416 8204d4b2 Eric Allman
                sleep(60);
417
        }
418
419
        return estat;
420
}
421
422
423
/*
424 158a49ba Eric Allman
**  PRINT_METADATA --- get and print the metadata
425
*/
426
427
void
428 eae1d3ec Eric Allman
print_metadata(gdp_gin_t *gin)
429 158a49ba Eric Allman
{
430
        EP_STAT estat;
431 eae1d3ec Eric Allman
        gdp_md_t *gmd;
432 21bc7eef Eric Allman
        gdp_recno_t nrecs;
433 158a49ba Eric Allman
434 eae1d3ec Eric Allman
        nrecs = gdp_gin_getnrecs(gin);
435 21bc7eef Eric Allman
        printf("Number of records: %" PRIgdp_recno "\n", nrecs);
436 eae1d3ec Eric Allman
        estat = gdp_gin_getmetadata(gin, &gmd);
437 158a49ba Eric Allman
        EP_STAT_CHECK(estat, goto fail0);
438
439 ada5f328 Eric Allman
        gdp_md_dump(gmd, stdout, 5, 0);
440 eae1d3ec Eric Allman
        gdp_md_free(gmd);
441 158a49ba Eric Allman
        return;
442
443
fail0:
444 9829d4ae Eric Allman
        ep_app_message(estat, "Could not read metadata!");
445 158a49ba Eric Allman
}
446
447 cbe2980a Eric Allman
void
448
usage(void)
449
{
450
        fprintf(stderr,
451 c3369218 Eric Allman
                        "Usage: %s [-a] [-b] [-c] [-d datetime] [-D dbgspec] [-f firstrec]\n"
452 2318b019 Eric Allman
                        "  [-G router_addr] [-L logfile] [-M] [-n nrecs] [-o outfile]\n"
453 ee0cddb9 Eric Allman
                        "  [-s] [-t] [-v] [-V] log_name\n"
454 8204d4b2 Eric Allman
                        "    -a  read asynchronously\n"
455 c3369218 Eric Allman
                        "    -b  output data in binary\n"
456 cbe2980a Eric Allman
                        "    -c  use callbacks\n"
457 65309098 Eric Allman
                        "    -d  first date/time to read from\n"
458 cbe2980a Eric Allman
                        "    -D  turn on debugging flags\n"
459
                        "    -f  first record number to read (from 1)\n"
460
                        "    -G  IP host to contact for gdp_router\n"
461
                        "    -L  set logging file name (for debugging)\n"
462
                        "    -M  show log metadata\n"
463
                        "    -n  set number of records to read (default all)\n"
464 2318b019 Eric Allman
                        "    -o  set output file name\n"
465 87a0bdac Eric Allman
                        "    -q  be quiet (don't print any metadata)\n"
466 cbe2980a Eric Allman
                        "    -s  subscribe to this log\n"
467 c8e97446 Eric Allman
                        "    -t  print data as text (instead of hexdump)\n"
468 ee0cddb9 Eric Allman
                        "    -v  print verbose output (include signature)\n"
469
                        "    -V  verify proof on returned data\n",
470 cbe2980a Eric Allman
                        ep_app_getprogname());
471
        exit(EX_USAGE);
472
}
473 158a49ba Eric Allman
474
/*
475 97696c1c Eric Allman
**  MAIN --- the name says it all
476
*/
477
478 47c6ea64 Eric Allman
int
479
main(int argc, char **argv)
480
{
481 eae1d3ec Eric Allman
        gdp_gin_t *gin = NULL;
482 a901db09 Eric Allman
        EP_STAT estat;
483 eae1d3ec Eric Allman
        gdp_name_t gobname;
484 a901db09 Eric Allman
        int opt;
485 5cd53c1a Eric Allman
        char *gdpd_addr = NULL;
486 9509f13b Eric Allman
        bool subscribe = false;
487 8204d4b2 Eric Allman
        bool async = false;
488 fe034bdb Eric Allman
        bool use_callbacks = false;
489 158a49ba Eric Allman
        bool showmetadata = false;
490 ee0cddb9 Eric Allman
        bool vrfy_proof = false;
491 552b93fd Eric Allman
        int32_t numrecs = 0;
492
        gdp_recno_t firstrec = 0;
493 591ae6e9 Eric Allman
        bool show_usage = false;
494 fd6e357c Eric Allman
        char *log_file_name = NULL;
495 b48f4199 Eric Allman
        gdp_iomode_t open_mode = GDP_MODE_RO;
496 65309098 Eric Allman
        const char *dtstr = NULL;
497 47c6ea64 Eric Allman
498 8baa1d3b Eric Allman
        ep_lib_init(EP_LIB_USEPTHREADS);        // initialize app errors, etc.
499 20dd7a58 Eric Allman
500 97696c1c Eric Allman
        // parse command-line options
501 c3369218 Eric Allman
        while ((opt = getopt(argc, argv, "abAcd:D:f:G:L:mMn:o:qstvV")) > 0)
502 47c6ea64 Eric Allman
        {
503 8baa1d3b Eric Allman
                errno = 0;                                                // avoid misleading messages
504 a901db09 Eric Allman
                switch (opt)
505
                {
506 b48f4199 Eric Allman
                  case 'A':                                // hidden flag for debugging only
507
                        open_mode = GDP_MODE_RA;
508
                        break;
509
510 8204d4b2 Eric Allman
                  case 'a':
511
                        // do asynchronous read
512
                        async = true;
513
                        break;
514
515 c3369218 Eric Allman
                  case 'b':
516
                        BinaryData = true;
517
                        break;
518
519 fe034bdb Eric Allman
                  case 'c':
520
                        // use callbacks
521
                        use_callbacks = true;
522
                        break;
523
524 65309098 Eric Allman
                  case 'd':
525
                        dtstr = optarg;
526
                        break;
527
528 a901db09 Eric Allman
                  case 'D':
529 97696c1c Eric Allman
                        // turn on debugging
530 a901db09 Eric Allman
                        ep_dbg_set(optarg);
531
                        break;
532 9509f13b Eric Allman
533 2e4a5d7d Eric Allman
                  case 'f':
534 97696c1c Eric Allman
                        // select the first record
535 2e4a5d7d Eric Allman
                        firstrec = atol(optarg);
536
                        break;
537
538 5cd53c1a Eric Allman
                  case 'G':
539
                        // set the port for connecting to the GDP daemon
540
                        gdpd_addr = optarg;
541
                        break;
542
543 fd6e357c Eric Allman
                  case 'L':
544
                        log_file_name = optarg;
545
                        break;
546
547 328d0948 Eric Allman
                  case 'm':
548 8baa1d3b Eric Allman
                        // multiread: obsolete
549
                        ep_app_warn("Multiread (-m) is deprecated; using Async (-a)");
550
                        async = true;
551 552b93fd Eric Allman
                        break;
552 328d0948 Eric Allman
553 158a49ba Eric Allman
                  case 'M':
554
                        showmetadata = true;
555
                        break;
556
557 2e4a5d7d Eric Allman
                  case 'n':
558 97696c1c Eric Allman
                        // select the number of records to be returned
559 2e4a5d7d Eric Allman
                        numrecs = atol(optarg);
560
                        break;
561
562 2318b019 Eric Allman
                  case 'o':
563
                        OutFile = fopen(optarg, "w");
564
                        if (OutFile == NULL)
565
                        {
566
                                ep_app_error("Cannot open output file %s", optarg);
567
                                exit(EX_CANTCREAT);
568
                        }
569
                        break;
570
571 87a0bdac Eric Allman
                  case 'q':
572
                        // be quiet (don't print metadata)
573
                        Quiet = true;
574
                        break;
575
576 9509f13b Eric Allman
                  case 's':
577 8baa1d3b Eric Allman
                        // subscribe to this log
578 9509f13b Eric Allman
                        subscribe = true;
579
                        break;
580 591ae6e9 Eric Allman
581 b42c4583 Eric Allman
                  case 't':
582
                        // print data as text
583
                        TextData = true;
584
                        break;
585
586 c8e97446 Eric Allman
                  case 'v':
587
                        PrintSig = true;
588 ee0cddb9 Eric Allman
589
                  case 'V':
590
                        vrfy_proof = true;
591 c8e97446 Eric Allman
                        break;
592
593 591ae6e9 Eric Allman
                  default:
594
                        show_usage = true;
595
                        break;
596 a901db09 Eric Allman
                }
597 47c6ea64 Eric Allman
        }
598 a901db09 Eric Allman
        argc -= optind;
599
        argv += optind;
600 47c6ea64 Eric Allman
601 bd278f2e Eric Allman
        if (firstrec != 0 && dtstr != NULL)
602 65309098 Eric Allman
        {
603 a0217621 Eric Allman
                ep_app_error("Cannot specify -f and -d");
604 65309098 Eric Allman
                exit(EX_USAGE);
605
        }
606
607 8204d4b2 Eric Allman
        int ntypes = 0;
608
        if (async)
609
                ntypes++;
610
        if (subscribe)
611
                ntypes++;
612
        if (ntypes > 1)
613
        {
614 c3369218 Eric Allman
                ep_app_error("Can only specify at most one of -a and -s");
615
                usage();
616 8204d4b2 Eric Allman
        }
617 c3369218 Eric Allman
        else if (ntypes < 1 && use_callbacks)
618 8baa1d3b Eric Allman
        {
619
                ep_app_warn("UseCallbacks (-c) flag does nothing without -a or -s");
620
        }
621 8204d4b2 Eric Allman
622 c3369218 Eric Allman
        ntypes = 0;
623
        if (TextData)
624
                ntypes++;
625
        if (BinaryData)
626
                ntypes++;
627
        if (ntypes > 1)
628
        {
629
                ep_app_error("Can only specify at most one of -b and -t");
630
                usage();
631
        }
632
633 8baa1d3b Eric Allman
        // we require a log name
634 591ae6e9 Eric Allman
        if (show_usage || argc <= 0)
635 cbe2980a Eric Allman
                usage();
636 47c6ea64 Eric Allman
637 fd6e357c Eric Allman
        if (log_file_name != NULL)
638
        {
639
                // open a log file (for timing measurements)
640
                LogFile = fopen(log_file_name, "a");
641
                if (LogFile == NULL)
642 a0217621 Eric Allman
                        ep_app_warn("Cannot open log file %s: %s",
643 fd6e357c Eric Allman
                                        log_file_name, strerror(errno));
644
                else
645
                        setlinebuf(LogFile);
646
        }
647
648 54a2c7b6 Eric Allman
        if (OutFile == NULL)
649
                OutFile = stdout;
650
651 97696c1c Eric Allman
        // initialize the GDP library
652 5cd53c1a Eric Allman
        estat = gdp_init(gdpd_addr);
653 a901db09 Eric Allman
        if (!EP_STAT_ISOK(estat))
654
        {
655
                ep_app_error("GDP Initialization failed");
656
                goto fail0;
657
        }
658 0c663d10 Eric Allman
659 2e4a5d7d Eric Allman
        // allow thread to settle to avoid interspersed debug output
660 44b5a101 Eric Allman
        ep_time_nanosleep(INT64_C(100000000));                // 100 msec
661 2e4a5d7d Eric Allman
662 97696c1c Eric Allman
        // parse the name (either base64-encoded or symbolic)
663 eae1d3ec Eric Allman
        estat = gdp_parse_name(argv[0], gobname);
664 22f2276a Eric Allman
        if (EP_STAT_ISFAIL(estat))
665 a901db09 Eric Allman
        {
666 8baa1d3b Eric Allman
                ep_app_message(estat, "illegal log name syntax:\n\t%s", argv[0]);
667 44e3ea02 Eric Allman
                exit(EX_USAGE);
668 a901db09 Eric Allman
        }
669 47c6ea64 Eric Allman
670 97696c1c Eric Allman
        // convert it to printable format and tell the user what we are doing
671 87a0bdac Eric Allman
        if (!Quiet)
672
        {
673 eae1d3ec Eric Allman
                gdp_pname_t gobpname;
674 87a0bdac Eric Allman
675 eae1d3ec Eric Allman
                gdp_printable_name(gobname, gobpname);
676 8baa1d3b Eric Allman
                fprintf(stderr, "Reading log %s\n", gobpname);
677 87a0bdac Eric Allman
        }
678 ecbc8f12 Eric Allman
679 ee0cddb9 Eric Allman
        // set up any special open parameters
680
        gdp_open_info_t *open_info = gdp_open_info_new();
681
        if (vrfy_proof)
682
                gdp_open_info_set_vrfy(open_info, true);
683
684 8baa1d3b Eric Allman
        // open the log; arguably this shouldn't be necessary
685 ee0cddb9 Eric Allman
        estat = gdp_gin_open(gobname, open_mode, open_info, &gin);
686
        gdp_open_info_free(open_info);
687 a901db09 Eric Allman
        if (!EP_STAT_ISOK(estat))
688
        {
689 8baa1d3b Eric Allman
                ep_app_message(estat, "Cannot open log %s", argv[0]);
690 a0217621 Eric Allman
                exit(EX_NOINPUT);
691 a901db09 Eric Allman
        }
692 47c6ea64 Eric Allman
693 65309098 Eric Allman
        // if we are converting a date/time string, set the local timezone
694
        if (dtstr != NULL)
695
                tzset();
696
697 158a49ba Eric Allman
        if (showmetadata)
698 eae1d3ec Eric Allman
                print_metadata(gin);
699 158a49ba Eric Allman
700 97696c1c Eric Allman
        // arrange to do the reading via one of the helper routines
701 8204d4b2 Eric Allman
        if (async)
702 eae1d3ec Eric Allman
                estat = do_async_read(gin, firstrec, numrecs, use_callbacks);
703 8baa1d3b Eric Allman
        else if (subscribe)
704
                estat = do_subscribe(gin, firstrec, dtstr, numrecs, use_callbacks);
705 9509f13b Eric Allman
        else
706 eae1d3ec Eric Allman
                estat = do_simpleread(gin, firstrec, dtstr, numrecs);
707 47c6ea64 Eric Allman
708 b201e69b Eric Allman
fail0:
709
        ;                                // silly compiler grammar
710
        int exitstat;
711
712
        if (!EP_STAT_ISFAIL(estat))                        // WARN or OK
713
                exitstat = EX_OK;
714
        else if (EP_STAT_IS_SAME(estat, GDP_STAT_NAK_NOROUTE))
715
                exitstat = EX_NOINPUT;
716
        else if (EP_STAT_ISABORT(estat))
717
                exitstat = EX_SOFTWARE;
718
        else
719
                exitstat = EX_UNAVAILABLE;
720
721 4af4baed Eric Allman
        if (ep_dbg_test(Dbg, 9))
722
        {
723
                char ebuf[100];
724
                ep_dbg_printf("Cleaning up, exitstat %d, estat %s\n",
725
                                exitstat, ep_stat_tostr(estat, ebuf, sizeof ebuf));
726
        }
727
728 97696c1c Eric Allman
        // might as well let the GDP know we're going away
729 eae1d3ec Eric Allman
        if (gin != NULL)
730 b201e69b Eric Allman
        {
731 eae1d3ec Eric Allman
                EP_STAT close_stat = gdp_gin_close(gin);
732 b201e69b Eric Allman
                if (!EP_STAT_ISOK(close_stat))
733 8baa1d3b Eric Allman
                        ep_app_message(close_stat, "cannot close log");
734 b201e69b Eric Allman
        }
735 97696c1c Eric Allman
736 0aa58d96 Eric Allman
        // this sleep is to watch for any extraneous results coming back
737
        if (ep_dbg_test(Dbg, 126))
738
        {
739
                int sleep_time = 40;
740
                ep_dbg_printf("Sleeping for %d seconds\n", sleep_time);
741
                while (sleep_time-- > 0)
742
                        ep_time_nanosleep(INT64_C(1000000000));                // one second
743
        }
744
745 97696c1c Eric Allman
        // might as well let the user know what's going on....
746 2dba893f Eric Allman
        if (EP_STAT_ISFAIL(estat))
747 b201e69b Eric Allman
                ep_app_message(estat, "exiting after %d records", NRead);
748 2dba893f Eric Allman
        else if (!Quiet)
749
                fprintf(stderr, "Exiting after %d records\n", NRead);
750 b201e69b Eric Allman
        return exitstat;
751 47c6ea64 Eric Allman
}