a7adac64a32af0925b99edd378afba63515de4ef
[debian/amanda] / perl / Amanda / Logfile.swg
1 /*
2  * Copyright (c) Zmanda, Inc.  All Rights Reserved.
3  *
4  * This library is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 2.1
6  * as published by the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
11  * License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
16  *
17  * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18  * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19  */
20
21 %module "Amanda::Logfile"
22 %include "amglue/amglue.swg"
23 %include "exception.i"
24 %include "amglue/dumpspecs.swg"
25 %import "Amanda/Cmdline.swg"
26
27 %{
28 #include <glib.h>
29 #include "logfile.h"
30 #include "find.h"
31 #include "diskfile.h" /* for the gross hack, below */
32 %}
33
34 %perlcode %{
35 =head1 NAME
36
37 Amanda::Logfile - manage Amanda trace logs
38
39 =head1 SYNOPSIS
40
41   use Amanda::Logfile qw(:logtype_t);
42   use Amanda::Config qw( :getconf config_dir_relative );
43
44   for my $logfile (Amanda::Logfile::find_log()) {
45     $logfile = config_dir_relative(getconf($CNF_LOGDIR)) . "/" . $logfile;
46
47     my $hdl = Amanda::Logfile::open_logfile($logfile);
48     while (my ($type, $prog, $str) = Amanda::Logfile::get_logline($hdl)) {
49       if ($type == $L_INFO) {
50         my $pname = Amanda::Logfile::program_t_to_string($prog);
51         print "Found info line from $pname: $str\n";
52       }
53     }
54     Amanda::Logfile::close_logfile($log);
55
56     my @dumps = Amanda::Logfile::search_logfile("TapeLabel-001", "19780615", $logfile, 1);
57
58     my @matching = Amanda::Logfile::dumps_match([@dumps], "myhost", "/usr", undef, undef, 0);
59     for my $dump (@matching) {
60       print "$dump->{'label'}:$dump->{'filenum'} = $dump->{'hostname'}:$dump->{'disk'}\n";
61     }
62   }
63
64 =head1 API STATUS
65
66 Stabilizing
67
68 =head1 RAW LOGFILE ACCESS
69
70 This section corresponds to the C C<logfile> module. 
71
72 Raw access to logfiles is accomplished by opening a logfile and
73 fetching log lines one by one via the C<get_logline> function.
74
75 A log line is represented by a list C<($type, $prog, $string)>
76 where C<$type> is one of the C<L_*> constants (available in export
77 tag C<logtype_t>), C<$prog> is one of the C<P_*> constants (available
78 in export tag C<program_t>), and C<$str> is the remainder of the line.
79
80 Both families of constants can be converted to symbolic names with
81 C<logtype_t_to_string> and C<program_t_to_string>, respectively.
82
83 =head2 FUNCTIONS
84
85 =over
86
87 =item C<open_logfile($filename)>
88
89 Opens a logfile for reading, returning an opaque log file handle.
90
91 =item C<close_logfile($handle)>
92
93 Closes a log file handle.
94
95 =item C<get_logline($handle)>
96
97 Return a list as described above representing the next log line in
98 C<$handle>, or nothing at the end of the logfile. 
99
100 =back
101
102 All of these functions can be imported by name if desired.
103
104 =head1 Amanda::Find::find_result_t objects
105
106 These objects contain information about dumps, as read from logfiles.
107 Instance variables are:
108
109 =over
110
111 =item C<timestamp>
112
113 =item C<hostname>
114
115 =item C<diskname>
116
117 =item C<level>
118
119 =item C<label>
120
121 =item C<filenum>
122
123 =item C<status>
124
125 =item C<partnum>
126
127 =item C<sec>
128
129 =item C<kb>
130
131 =back
132
133 Note that the format for these variables are based on that found in the
134 logfiles.  In particular, C<partnum> is a string, usually with a slash (C</>)
135 in it.  Also, C<timestamp> is the timestamp for the run in which the client
136 dump took place, and not for the timestamp of the logfile.
137
138 =head1 HIGHER-LEVEL FUNCTIONS
139
140 Functions in this section extract information from logfiles.
141
142 =over
143
144 =item C<find_log()>
145
146 Return a list of logfiles for active tapes.  The tapelist must be loaded before
147 this function is called (see L<Amanda::Tapelist>).
148
149 =item C<search_logfile($label, $datestamp, $logfile, $add_missing_disks)>
150
151 Return all results in C<$logfile> matching C<$label> and C<$datestamp>.
152 If C<$add_missing_disks> is true, then any disks in the logfile
153 not present in the disklist are added to the disklist; otherwise,
154 such dumps are skipped.
155
156 =item C<dumps_match([@results], $hostname, $diskname, $datestamp, $level, $ok)>
157
158 Return a filtered version of C<@results> containing only results that match the 
159 given expressions.  If C<$ok> is true, don't match partial results.  Note that
160 C<$level> is given as a string, since it is a match expression.
161
162 All of these functions can be imported by name.
163
164 =back
165
166 =cut
167 %}
168
169 amglue_export_ok(
170     open_logfile get_logline close_logfile
171 );
172
173
174 amglue_add_enum_tag_fns(logtype_t);
175 amglue_add_constant(L_BOGUS, logtype_t);
176 amglue_add_constant(L_FATAL, logtype_t);
177 amglue_add_constant(L_ERROR, logtype_t);
178 amglue_add_constant(L_WARNING, logtype_t);
179 amglue_add_constant(L_INFO, logtype_t);
180 amglue_add_constant(L_SUMMARY, logtype_t);
181 amglue_add_constant(L_START, logtype_t);
182 amglue_add_constant(L_FINISH, logtype_t);
183 amglue_add_constant(L_DISK, logtype_t);
184 amglue_add_constant(L_DONE, logtype_t);
185 amglue_add_constant(L_PART, logtype_t);
186 amglue_add_constant(L_PARTPARTIAL, logtype_t);
187 amglue_add_constant(L_SUCCESS, logtype_t);
188 amglue_add_constant(L_PARTIAL, logtype_t);
189 amglue_add_constant(L_FAIL, logtype_t);
190 amglue_add_constant(L_STRANGE, logtype_t);
191 amglue_add_constant(L_CHUNK, logtype_t);
192 amglue_add_constant(L_CHUNKSUCCESS, logtype_t);
193 amglue_add_constant(L_STATS, logtype_t);
194 amglue_add_constant(L_MARKER, logtype_t);
195 amglue_add_constant(L_CONT, logtype_t);
196
197 amglue_add_enum_tag_fns(program_t);
198 amglue_add_constant(P_UNKNOWN, program_t);
199 amglue_add_constant(P_PLANNER, program_t);
200 amglue_add_constant(P_DRIVER, program_t);
201 amglue_add_constant(P_REPORTER, program_t);
202 amglue_add_constant(P_DUMPER, program_t);
203 amglue_add_constant(P_CHUNKER, program_t);
204 amglue_add_constant(P_TAPER, program_t);
205 amglue_add_constant(P_AMFLUSH, program_t);
206
207 /* TODO: support for writing logfiles is omitted for the moment. */
208
209 %inline %{
210 /* open_ and close_logfile are both simple wrappers around fopen/fclose. */
211 typedef FILE loghandle;
212
213 loghandle *open_logfile(char *filename) {
214     return fopen(filename, "r");
215 }
216 %}
217
218 %inline %{
219 void close_logfile(loghandle *logfile) {
220     if (logfile) fclose(logfile);
221 }
222 %}
223
224 /* We fake the return type of get_logline, and use a typemap to
225  * slurp curstr, curprog, and curlog into a return value.  */
226 %{
227 typedef int LOGLINE_RETURN;
228 %}
229 %typemap(out) LOGLINE_RETURN {
230     if ($1 != 0) {
231         EXTEND(SP, 3);
232         $result = sv_2mortal(newSViv(curlog));
233         argvi++;
234         $result = sv_2mortal(newSViv(curprog));
235         argvi++;
236         $result = sv_2mortal(newSVpv(curstr, 0));
237         argvi++;
238     }
239     /* otherwise (end of logfile) return an empty list */
240 }
241 LOGLINE_RETURN get_logline(FILE *logfile);
242
243 typedef struct {
244     %extend {
245         /* destructor */
246         ~find_result_t() {
247             find_result_t *selfp = self;
248             free_find_result(&selfp);
249         }
250     }
251
252     %immutable;
253     char *timestamp;
254     char *hostname;
255     char *diskname;
256     int level;
257     char *label;
258     off_t filenum;
259     char *status;
260     char *partnum;
261     double sec;
262     size_t kb;
263     %mutable;
264 } find_result_t;
265
266 /* This typemap is used in a few functions.  It converts a linked list of find_result_t's
267  * into an array of same, de-linking the list in the process.  This gives ownership of the
268  * objects to perl, which is consistent with the C interface to this module.
269  */
270 %typemap(out) find_result_t * {
271     find_result_t *iter;
272     int len;
273
274     /* measure the list and make room on the perl stack */
275     for (len=0, iter=$1; iter; iter=iter->next) len++;
276     EXTEND(SP, len);
277
278     iter = $1;
279     while (iter) {
280         find_result_t *next;
281         /* Let SWIG take ownership of the object */
282         $result = SWIG_NewPointerObj(iter, $descriptor(find_result_t *), SWIG_OWNER | SWIG_SHADOW);
283         argvi++;
284
285         /* null out the 'next' field */
286         next = iter->next;
287         iter->next = NULL;
288         iter = next;
289     }
290 }
291
292 /* Similarly, on input we link an array full of find_result_t's.  The list is then
293  * unlinked on return.  Note that the array is supplied as an arrayref (since it's 
294  * usually the first argument).
295  */
296 %typemap(in) find_result_t * {
297     AV *av;
298     I32 len, i;
299     find_result_t *head = NULL, *tail = NULL;
300
301     if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
302         SWIG_exception(SWIG_TypeError, "expected an arrayref of find_result_t's");
303     }
304
305     av = (AV *)SvRV($input);
306     len = av_len(av) + 1;
307
308     for (i = 0; i < len; i++) {
309         SV **val = av_fetch(av, i, 0);
310         find_result_t *r;
311
312         if (!val || SWIG_ConvertPtr(*val, (void **)&r, $descriptor(find_result_t *), 0) == -1) {
313             SWIG_exception(SWIG_TypeError, "array member is not a find_result_t");
314         }
315
316         if (!head) {
317             head = tail = r;
318         } else {
319             tail->next = r;
320             tail = r;
321         }
322
323         tail->next = NULL;
324     }
325
326     /* point to the head of that list */
327     $1 = head;
328 }
329
330 %typemap(freearg) find_result_t * {
331     find_result_t *iter = $1, *next;
332
333     /* undo all the links we added earlier */
334     while (iter) {
335         next = iter->next;
336         iter->next = NULL;
337         iter = next;
338     }
339 }
340
341 %typemap(out) char ** {
342     char **iter;
343     int len, i;
344     
345     /* measure the length of the array and make sure perl has enough room */
346     for (len=0, iter=$1; *iter; iter++) len++;
347     EXTEND(SP, len);
348
349     /* now copy it to the perl stack */
350     for (i=0, iter=$1; *iter; iter++, i++) {
351         $result = sv_2mortal(newSVpv(*iter, 0));
352         argvi++;
353     }
354 }
355
356 amglue_export_ok(
357     find_log search_logfile dumps_match
358 );
359
360 char **find_log(void);
361
362 %rename(search_logfile) search_logfile_wrap;
363 %inline %{
364 find_result_t *search_logfile_wrap(char *label, char *datestamp, 
365                                    char *logfile, int add_missing_disks) {
366     find_result_t *rv = NULL;
367
368     /* We use a static variable to collect any unrecognized disks */
369     static disklist_t unrecognized_disks = { NULL, NULL };
370
371     search_logfile(&rv, label, datestamp, logfile, 
372         add_missing_disks? &unrecognized_disks : NULL);
373
374     return rv;
375 }
376 %}
377
378 find_result_t *dumps_match(find_result_t *output_find, char *hostname,
379                            char *diskname, char *datestamp, char *level, int ok);
380
381 find_result_t *dumps_match_dumpspecs(find_result_t *output_find,
382     amglue_dumpspec_list *dumpspecs,
383     gboolean ok);