2 * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
8 * This program 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 General Public License
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 %module "Amanda::Logfile"
22 %include "amglue/amglue.swg"
23 %include "exception.i"
24 %include "amglue/dumpspecs.swg"
25 %import "Amanda/Cmdline.swg"
27 %include "Amanda/Logfile.pod"
33 #include "diskfile.h" /* for the gross hack, below */
37 open_logfile get_logline close_logfile
42 amglue_add_enum_tag_fns(logtype_t);
43 amglue_add_constant(L_BOGUS, logtype_t);
44 amglue_add_constant(L_FATAL, logtype_t);
45 amglue_add_constant(L_ERROR, logtype_t);
46 amglue_add_constant(L_WARNING, logtype_t);
47 amglue_add_constant(L_INFO, logtype_t);
48 amglue_add_constant(L_SUMMARY, logtype_t);
49 amglue_add_constant(L_START, logtype_t);
50 amglue_add_constant(L_FINISH, logtype_t);
51 amglue_add_constant(L_DISK, logtype_t);
52 amglue_add_constant(L_DONE, logtype_t);
53 amglue_add_constant(L_PART, logtype_t);
54 amglue_add_constant(L_PARTPARTIAL, logtype_t);
55 amglue_add_constant(L_SUCCESS, logtype_t);
56 amglue_add_constant(L_PARTIAL, logtype_t);
57 amglue_add_constant(L_FAIL, logtype_t);
58 amglue_add_constant(L_STRANGE, logtype_t);
59 amglue_add_constant(L_CHUNK, logtype_t);
60 amglue_add_constant(L_CHUNKSUCCESS, logtype_t);
61 amglue_add_constant(L_STATS, logtype_t);
62 amglue_add_constant(L_MARKER, logtype_t);
63 amglue_add_constant(L_CONT, logtype_t);
64 amglue_copy_to_tag(logtype_t, constants);
66 amglue_add_enum_tag_fns(program_t);
67 amglue_add_constant(P_UNKNOWN, program_t);
68 amglue_add_constant(P_PLANNER, program_t);
69 amglue_add_constant(P_DRIVER, program_t);
70 amglue_add_constant(P_REPORTER, program_t);
71 amglue_add_constant(P_DUMPER, program_t);
72 amglue_add_constant(P_CHUNKER, program_t);
73 amglue_add_constant(P_TAPER, program_t);
74 amglue_add_constant(P_AMFLUSH, program_t);
75 amglue_add_constant(P_AMDUMP, program_t);
76 amglue_add_constant(P_AMIDXTAPED, program_t);
77 amglue_add_constant(P_AMFETCHDUMP, program_t);
78 amglue_add_constant(P_AMCHECKDUMP, program_t);
79 amglue_add_constant(P_AMVAULT, program_t);
80 amglue_copy_to_tag(program_t, constants);
82 /* TODO: support for writing logfiles is omitted for the moment. */
85 /* open_ and close_logfile are both simple wrappers around fopen/fclose. */
86 typedef FILE loghandle;
88 static loghandle *open_logfile(char *filename) {
89 return fopen(filename, "r");
94 static void close_logfile(loghandle *logfile) {
95 if (logfile) fclose(logfile);
99 /* We fake the return type of get_logline, and use a typemap to
100 * slurp curstr, curprog, and curlog into a return value. */
102 typedef int LOGLINE_RETURN;
104 %typemap(out) LOGLINE_RETURN {
107 $result = sv_2mortal(newSViv(curlog));
109 $result = sv_2mortal(newSViv(curprog));
111 $result = sv_2mortal(newSVpv(curstr, 0));
114 /* otherwise (end of logfile) return an empty list */
116 LOGLINE_RETURN get_logline(FILE *logfile);
118 %rename(log_add) log_add_;
119 %rename(log_add_full) log_add_full_;
121 static void log_add_(logtype_t typ, char *message)
123 log_add(typ, "%s", message);
125 static void log_add_full_(logtype_t typ, char *pname, char *message)
127 log_add_full(typ, pname, "%s", message);
131 void log_rename(char *datestamp);
137 find_result_t *selfp = self;
138 free_find_result(&selfp);
144 char *write_timestamp;
162 /* This typemap is used in a few functions. It converts a linked list of find_result_t's
163 * into an array of same, de-linking the list in the process. This gives ownership of the
164 * objects to perl, which is consistent with the C interface to this module.
166 %typemap(out) find_result_t * {
170 /* measure the list and make room on the perl stack */
171 for (len=0, iter=$1; iter; iter=iter->next) len++;
177 /* Let SWIG take ownership of the object */
178 $result = SWIG_NewPointerObj(iter, $descriptor(find_result_t *), SWIG_OWNER | SWIG_SHADOW);
181 /* null out the 'next' field */
188 /* Similarly, on input we link an array full of find_result_t's. The list is then
189 * unlinked on return. Note that the array is supplied as an arrayref (since it's
190 * usually the first argument).
192 %typemap(in) find_result_t * {
195 find_result_t *head = NULL, *tail = NULL;
197 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
198 SWIG_exception(SWIG_TypeError, "expected an arrayref of find_result_t's");
201 av = (AV *)SvRV($input);
202 len = av_len(av) + 1;
204 for (i = 0; i < len; i++) {
205 SV **val = av_fetch(av, i, 0);
208 if (!val || SWIG_ConvertPtr(*val, (void **)&r, $descriptor(find_result_t *), 0) == -1) {
209 SWIG_exception(SWIG_TypeError, "array member is not a find_result_t");
222 /* point to the head of that list */
226 %typemap(freearg) find_result_t * {
227 find_result_t *iter = $1, *next;
229 /* undo all the links we added earlier */
237 %typemap(out) char ** {
241 /* measure the length of the array and make sure perl has enough room */
242 for (len=0, iter=$1; *iter; iter++) len++;
245 /* now copy it to the perl stack */
246 for (i=0, iter=$1; *iter; iter++, i++) {
247 $result = sv_2mortal(newSVpv(*iter, 0));
253 find_log search_logfile dumps_match log_rename
256 char **find_log(void);
258 %rename(search_logfile) search_logfile_wrap;
260 static find_result_t *search_logfile_wrap(char *label, char *datestamp,
261 char *logfile, int add_missing_disks) {
262 find_result_t *rv = NULL;
264 /* We use a static variable to collect any unrecognized disks */
265 static disklist_t unrecognized_disks = { NULL, NULL };
267 search_logfile(&rv, label, datestamp, logfile,
268 add_missing_disks? &unrecognized_disks : NULL);
274 %rename(search_holding_disk) search_holding_disk_wrap;
276 static find_result_t *search_holding_disk_wrap(void) {
277 find_result_t *rv = NULL;
278 static disklist_t unrecognized_disks = { NULL, NULL };
279 search_holding_disk(&rv, &unrecognized_disks);
284 find_result_t *dumps_match(find_result_t *output_find, char *hostname,
285 char *diskname, char *datestamp, char *level, int ok);
287 find_result_t *dumps_match_dumpspecs(find_result_t *output_find,
288 amglue_dumpspec_list *dumpspecs,
292 amanda_log_handler_t *amanda_log_trace_log;
295 $amanda_log_trace_log
300 find_all_logs find_latest_log
301 get_current_log_timestamp
309 my $logdir = shift @_ || config_dir_relative(getconf($CNF_LOGDIR));
311 opendir my $logdh, $logdir or die("can't read $logdir");
312 my @logfiles = sort grep { m{^log\.\d+\.\d+$} } readdir $logdh;
319 my $logdir = shift @_;
320 my @logs = find_all_logs($logdir || ());
327 sub get_current_log_timestamp
329 my $logfile = Amanda::Config::config_dir_relative(
330 Amanda::Config::getconf($Amanda::Config::CNF_LOGDIR)) . "/log";
332 Amanda::Debug::warning("no current logfile '$logfile'");
336 my $logh = open_logfile("$logfile");
338 Amanda::Debug::warning("could not open logfile '$logfile'");
341 while (my ($type, $prog, $str) = get_logline($logh)) {
342 if ($type == $L_START) {
343 my ($ts) = ($str =~ /date (\d+)/);
348 # no timestamp, apparently
349 Amanda::Debug::warning("no current timestamp found in logfile");
354 my ($size, $duration, $orig_kb) = @_;
356 $duration = 0.1 if $duration <= 0; # prevent division by zero
358 my $kps = "$kb.0"/$duration; # Perlish cast from BigInt to float
360 if (defined $orig_kb) {
361 return sprintf("[sec %f bytes %s kps %f orig-kb %s]", $duration, $size, $kps, $orig_kb);
363 return sprintf("[sec %f bytes %s kps %f]", $duration, $size, $kps);