1/* 2 * Copyright (c) 2007-2013 Zmanda, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * 18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300 19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com 20 */ 21 22%module "Amanda::Logfile" 23%include "amglue/amglue.swg" 24%include "exception.i" 25%include "amglue/dumpspecs.swg" 26%import "Amanda/Cmdline.swg" 27 28%include "Amanda/Logfile.pod" 29 30%{ 31#include <glib.h> 32#include "logfile.h" 33#include "find.h" 34#include "diskfile.h" /* for the gross hack, below */ 35%} 36 37amglue_export_ok( 38 open_logfile get_logline close_logfile 39 log_add log_add_full 40); 41 42 43amglue_add_enum_tag_fns(logtype_t); 44amglue_add_constant(L_BOGUS, logtype_t); 45amglue_add_constant(L_FATAL, logtype_t); 46amglue_add_constant(L_ERROR, logtype_t); 47amglue_add_constant(L_WARNING, logtype_t); 48amglue_add_constant(L_INFO, logtype_t); 49amglue_add_constant(L_SUMMARY, logtype_t); 50amglue_add_constant(L_START, logtype_t); 51amglue_add_constant(L_FINISH, logtype_t); 52amglue_add_constant(L_DISK, logtype_t); 53amglue_add_constant(L_DONE, logtype_t); 54amglue_add_constant(L_PART, logtype_t); 55amglue_add_constant(L_PARTPARTIAL, logtype_t); 56amglue_add_constant(L_SUCCESS, logtype_t); 57amglue_add_constant(L_PARTIAL, logtype_t); 58amglue_add_constant(L_FAIL, logtype_t); 59amglue_add_constant(L_STRANGE, logtype_t); 60amglue_add_constant(L_CHUNK, logtype_t); 61amglue_add_constant(L_CHUNKSUCCESS, logtype_t); 62amglue_add_constant(L_STATS, logtype_t); 63amglue_add_constant(L_MARKER, logtype_t); 64amglue_add_constant(L_CONT, logtype_t); 65amglue_copy_to_tag(logtype_t, constants); 66 67amglue_add_enum_tag_fns(program_t); 68amglue_add_constant(P_UNKNOWN, program_t); 69amglue_add_constant(P_PLANNER, program_t); 70amglue_add_constant(P_DRIVER, program_t); 71amglue_add_constant(P_REPORTER, program_t); 72amglue_add_constant(P_DUMPER, program_t); 73amglue_add_constant(P_CHUNKER, program_t); 74amglue_add_constant(P_TAPER, program_t); 75amglue_add_constant(P_AMFLUSH, program_t); 76amglue_add_constant(P_AMDUMP, program_t); 77amglue_add_constant(P_AMIDXTAPED, program_t); 78amglue_add_constant(P_AMFETCHDUMP, program_t); 79amglue_add_constant(P_AMCHECKDUMP, program_t); 80amglue_add_constant(P_AMVAULT, program_t); 81amglue_copy_to_tag(program_t, constants); 82 83/* TODO: support for writing logfiles is omitted for the moment. */ 84 85%inline %{ 86/* open_ and close_logfile are both simple wrappers around fopen/fclose. */ 87typedef FILE loghandle; 88 89static loghandle *open_logfile(char *filename) { 90 return fopen(filename, "r"); 91} 92%} 93 94%inline %{ 95static void close_logfile(loghandle *logfile) { 96 if (logfile) fclose(logfile); 97} 98%} 99 100/* We fake the return type of get_logline, and use a typemap to 101 * slurp curstr, curprog, and curlog into a return value. */ 102%{ 103typedef int LOGLINE_RETURN; 104%} 105%typemap(out) LOGLINE_RETURN { 106 if ($1 != 0) { 107 EXTEND(SP, 3); 108 $result = sv_2mortal(newSViv(curlog)); 109 argvi++; 110 $result = sv_2mortal(newSViv(curprog)); 111 argvi++; 112 $result = sv_2mortal(newSVpv(curstr, 0)); 113 argvi++; 114 } 115 /* otherwise (end of logfile) return an empty list */ 116} 117LOGLINE_RETURN get_logline(FILE *logfile); 118 119%rename(log_add) log_add_; 120%rename(log_add_full) log_add_full_; 121%inline %{ 122static void log_add_(logtype_t typ, char *message) 123{ 124 log_add(typ, "%s", message); 125} 126static void log_add_full_(logtype_t typ, char *pname, char *message) 127{ 128 log_add_full(typ, pname, "%s", message); 129} 130%} 131 132void log_rename(char *datestamp); 133 134typedef struct { 135 %extend { 136 /* destructor */ 137 ~find_result_t() { 138 find_result_t *selfp = self; 139 free_find_result(&selfp); 140 } 141 } 142 143 %immutable; 144 char *timestamp; 145 char *write_timestamp; 146 char *hostname; 147 char *diskname; 148 int level; 149 char *label; 150 off_t filenum; 151 char *status; 152 char *dump_status; 153 char *message; 154 int partnum; 155 int totalparts; 156 double sec; 157 off_t bytes; 158 off_t kb; 159 off_t orig_kb; 160 %mutable; 161} find_result_t; 162 163/* This typemap is used in a few functions. It converts a linked list of find_result_t's 164 * into an array of same, de-linking the list in the process. This gives ownership of the 165 * objects to perl, which is consistent with the C interface to this module. 166 */ 167%typemap(out) find_result_t * { 168 find_result_t *iter; 169 int len; 170 171 /* measure the list and make room on the perl stack */ 172 for (len=0, iter=$1; iter; iter=iter->next) len++; 173 EXTEND(SP, len); 174 175 iter = $1; 176 while (iter) { 177 find_result_t *next; 178 /* Let SWIG take ownership of the object */ 179 $result = SWIG_NewPointerObj(iter, $descriptor(find_result_t *), SWIG_OWNER | SWIG_SHADOW); 180 argvi++; 181 182 /* null out the 'next' field */ 183 next = iter->next; 184 iter->next = NULL; 185 iter = next; 186 } 187} 188 189/* Similarly, on input we link an array full of find_result_t's. The list is then 190 * unlinked on return. Note that the array is supplied as an arrayref (since it's 191 * usually the first argument). 192 */ 193%typemap(in) find_result_t * { 194 AV *av; 195 I32 len, i; 196 find_result_t *head = NULL, *tail = NULL; 197 198 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) { 199 SWIG_exception(SWIG_TypeError, "expected an arrayref of find_result_t's"); 200 } 201 202 av = (AV *)SvRV($input); 203 len = av_len(av) + 1; 204 205 for (i = 0; i < len; i++) { 206 SV **val = av_fetch(av, i, 0); 207 find_result_t *r; 208 209 if (!val || SWIG_ConvertPtr(*val, (void **)&r, $descriptor(find_result_t *), 0) == -1) { 210 SWIG_exception(SWIG_TypeError, "array member is not a find_result_t"); 211 } 212 213 if (!head) { 214 head = tail = r; 215 } else { 216 tail->next = r; 217 tail = r; 218 } 219 220 tail->next = NULL; 221 } 222 223 /* point to the head of that list */ 224 $1 = head; 225} 226 227%typemap(freearg) find_result_t * { 228 find_result_t *iter = $1, *next; 229 230 /* undo all the links we added earlier */ 231 while (iter) { 232 next = iter->next; 233 iter->next = NULL; 234 iter = next; 235 } 236} 237 238%typemap(out) char ** { 239 char **iter; 240 int len, i; 241 242 /* measure the length of the array and make sure perl has enough room */ 243 for (len=0, iter=$1; *iter; iter++) len++; 244 EXTEND(SP, len); 245 246 /* now copy it to the perl stack */ 247 for (i=0, iter=$1; *iter; iter++, i++) { 248 $result = sv_2mortal(newSVpv(*iter, 0)); 249 argvi++; 250 } 251} 252 253amglue_export_ok( 254 find_log search_logfile dumps_match log_rename 255); 256 257char **find_log(void); 258 259%rename(search_logfile) search_logfile_wrap; 260%inline %{ 261static find_result_t *search_logfile_wrap(char *label, char *datestamp, 262 char *logfile, int add_missing_disks) { 263 find_result_t *rv = NULL; 264 265 /* We use a static variable to collect any unrecognized disks */ 266 static disklist_t unrecognized_disks = { NULL, NULL }; 267 268 search_logfile(&rv, label, datestamp, logfile, 269 add_missing_disks? &unrecognized_disks : NULL); 270 271 return rv; 272} 273%} 274 275%rename(search_holding_disk) search_holding_disk_wrap; 276%inline %{ 277static find_result_t *search_holding_disk_wrap(void) { 278 find_result_t *rv = NULL; 279 static disklist_t unrecognized_disks = { NULL, NULL }; 280 search_holding_disk(&rv, &unrecognized_disks); 281 return rv; 282} 283%} 284 285find_result_t *dumps_match(find_result_t *output_find, char *hostname, 286 char *diskname, char *datestamp, char *level, int ok); 287 288find_result_t *dumps_match_dumpspecs(find_result_t *output_find, 289 amglue_dumpspec_list *dumpspecs, 290 gboolean ok); 291 292%immutable; 293amanda_log_handler_t *amanda_log_trace_log; 294%mutable; 295amglue_export_ok( 296 $amanda_log_trace_log 297); 298 299 300amglue_export_ok( 301 find_all_logs find_latest_log 302 get_current_log_timestamp 303 make_stats 304); 305 306%perlcode %{ 307 308use Amanda::Config qw ( :init :getconf config_dir_relative ); 309use Amanda::Debug; 310 311sub find_all_logs 312{ 313 my $logdir = shift @_ || config_dir_relative(getconf($CNF_LOGDIR)); 314 315 opendir my $logdh, $logdir or die("can't read $logdir"); 316 my @logfiles = sort grep { m{^log\.\d+\.\d+$} } readdir $logdh; 317 318 return @logfiles; 319} 320 321sub find_latest_log 322{ 323 my $logdir = shift @_; 324 my @logs = find_all_logs($logdir || ()); 325 return $logs[-1]; 326} 327 328sub get_current_log_timestamp 329{ 330 my $logfile = config_dir_relative(getconf($CNF_LOGDIR)) . "/log"; 331 if (! -f $logfile) { 332 Amanda::Debug::warning("no current logfile '$logfile'"); 333 return undef; 334 } 335 336 my $logh = open_logfile("$logfile"); 337 if (!$logh) { 338 Amanda::Debug::warning("could not open logfile '$logfile'"); 339 return undef; 340 } 341 while (my ($type, $prog, $str) = get_logline($logh)) { 342 if ($type == $L_START) { 343 my ($ts) = ($str =~ /date (\d+)/); 344 return $ts if $ts; 345 } 346 } 347 348 # no timestamp, apparently 349 Amanda::Debug::warning("no current timestamp found in logfile"); 350 return undef; 351} 352 353sub make_stats { 354 my ($size, $duration, $orig_kb) = @_; 355 356 $duration = 0.1 if $duration <= 0; # prevent division by zero 357 my $kb = $size/1024; 358 my $kps = "$kb.0"/$duration; # Perlish cast from BigInt to float 359 360 if (defined $orig_kb) { 361 return sprintf("[sec %f bytes %s kps %f orig-kb %s]", $duration, $size, $kps, $orig_kb); 362 } else { 363 return sprintf("[sec %f bytes %s kps %f]", $duration, $size, $kps); 364 } 365} 366 367%} 368