smarbs 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +23 -0
- data/History.txt +3 -0
- data/Manifest.txt +28 -0
- data/README.txt +88 -0
- data/Rakefile +10 -0
- data/bin/smarbs +11 -0
- data/lib/backup.rb +275 -0
- data/lib/data/configuration.txt +209 -0
- data/lib/data/iconblue.png +0 -0
- data/lib/data/icongreen.png +0 -0
- data/lib/data/iconred.png +0 -0
- data/lib/data/intro.txt +16 -0
- data/lib/data/outro.txt +15 -0
- data/lib/helpers.rb +438 -0
- data/lib/log.rb +214 -0
- data/lib/script.rb +217 -0
- data/lib/smarbs.rb +5 -0
- data/lib/syslog.rb +98 -0
- data/lib/types.rb +172 -0
- data/test/smarbs_test.rb +114 -0
- data/test/test_backup.rb +171 -0
- data/test/test_helpers.rb +500 -0
- data/test/test_log.rb +128 -0
- data/test/test_script.rb +118 -0
- data/test/test_smarbs.rb +131 -0
- data/test/test_smarbs_test.rb +76 -0
- data/test/test_suite.rb +11 -0
- data/test/test_types.rb +141 -0
- metadata +107 -0
data/lib/helpers.rb
ADDED
@@ -0,0 +1,438 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'types'
|
3
|
+
require 'smarbs'
|
4
|
+
|
5
|
+
class ConfigString
|
6
|
+
# Takes as args the arguments to the specific type (like positive), as desc
|
7
|
+
# the description of the value, and as defaults an Array or a single default
|
8
|
+
# value that is shown when no other value is added.
|
9
|
+
def initialize(name, args, desc, defaults)
|
10
|
+
@list = false
|
11
|
+
@positive = false
|
12
|
+
args.split(",").each{|arg| eval("@#{arg} = true") unless arg.empty?}
|
13
|
+
@desc = desc
|
14
|
+
@defaults = defaults
|
15
|
+
@defaults = "" if @defaults.empty?
|
16
|
+
@name = name
|
17
|
+
clear
|
18
|
+
value
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the value, as an Array if list is false, as a single value
|
22
|
+
# otherwise. If the value is empty, return the default value(s).
|
23
|
+
def value
|
24
|
+
val = nil
|
25
|
+
if @value.empty? then
|
26
|
+
set(@defaults)
|
27
|
+
val = @value
|
28
|
+
clear
|
29
|
+
else
|
30
|
+
val = @value
|
31
|
+
end
|
32
|
+
if @list then
|
33
|
+
val
|
34
|
+
else
|
35
|
+
val[0]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the name of this option.
|
40
|
+
def name
|
41
|
+
@name
|
42
|
+
end
|
43
|
+
|
44
|
+
# Prints out the configfile-text with description.
|
45
|
+
def to_s
|
46
|
+
if @list then
|
47
|
+
([@desc] + value.collect{|value| format(value)}).join("\n" + name + " ")
|
48
|
+
else
|
49
|
+
@desc + "\n" + name + " " + format(value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Adds the value(s) to @value (can be an Array). Doesn't strip!
|
54
|
+
def add(value)
|
55
|
+
if value.class == Array then
|
56
|
+
value.each{ |v| addvalue(v) }
|
57
|
+
else
|
58
|
+
addvalue(value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sets the value as value of the object (can be an Array).
|
63
|
+
def set(value)
|
64
|
+
clear
|
65
|
+
add(value)
|
66
|
+
end
|
67
|
+
|
68
|
+
def clear
|
69
|
+
@value = []
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
|
75
|
+
# Adds the single string-value to @value
|
76
|
+
def addvalue(string)
|
77
|
+
raise "Only one '#{name}' allowed!" unless (@value.size == 0 or @list)
|
78
|
+
@value << check(string) unless @value.include?(check(string))
|
79
|
+
end
|
80
|
+
|
81
|
+
def check(string)
|
82
|
+
string.to_s
|
83
|
+
end
|
84
|
+
|
85
|
+
def format(value)
|
86
|
+
value.to_s
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class ConfigDirectory < ConfigString
|
91
|
+
def check(string)
|
92
|
+
string.strip!
|
93
|
+
string.chop! if string[-1, 1] == "/" and string.size > 1
|
94
|
+
string
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class ConfigSize < ConfigString
|
99
|
+
def check(value)
|
100
|
+
if value.class == Size then
|
101
|
+
value
|
102
|
+
else
|
103
|
+
Size.new(value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def format(value)
|
108
|
+
value.short
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class ConfigBoolean < ConfigString
|
113
|
+
def check(value)
|
114
|
+
if value == true or value == false then
|
115
|
+
value
|
116
|
+
else
|
117
|
+
value.downcase == "yes"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def format(value)
|
122
|
+
if value then "yes" else "no" end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class ConfigInteger < ConfigString
|
127
|
+
def check(value)
|
128
|
+
raise "Format #{value} not valid for an integer in '#{name}'!" unless value.to_i.to_s == value if value.class == String
|
129
|
+
value = value.to_i
|
130
|
+
raise "'#{name}' must be positive, you set it to #{value}!" unless value >= 0 if @positive
|
131
|
+
value
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class ConfigExclude < ConfigString
|
136
|
+
def initialize(name, args, desc, defaults)
|
137
|
+
super(name, args + ",list", desc, defaults)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class ConfigTemplate
|
142
|
+
|
143
|
+
# Initializes a new ConfigTemplate and creates the internal structures needed.
|
144
|
+
# To read the actual data use read_template.
|
145
|
+
def initialize
|
146
|
+
@hash = Hash.new
|
147
|
+
@order = Array.new
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns everything within this ConfigTemplate as a parseable configfile
|
151
|
+
# text.
|
152
|
+
def to_s
|
153
|
+
out = ""
|
154
|
+
@order.each do |section|
|
155
|
+
out += preference_text(section[0]) + "\n\n"
|
156
|
+
section[1..-1].each do |option|
|
157
|
+
out += @hash[option].to_s + "\n\n"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
out
|
161
|
+
end
|
162
|
+
|
163
|
+
def clear
|
164
|
+
@order.each do |section|
|
165
|
+
section[1..-1].each do |option|
|
166
|
+
@hash[option].clear
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Reads the template file at the given path and
|
172
|
+
def read_template(path)
|
173
|
+
sections = nil
|
174
|
+
File.open(path, "r") do |file|
|
175
|
+
sections = file.readlines
|
176
|
+
sections.each { |line| line.rstrip! }
|
177
|
+
sections = sections.join("\n").split("\n\n")
|
178
|
+
end
|
179
|
+
|
180
|
+
sections.each do |section|
|
181
|
+
parse_section(section)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Parses the string (or Array of strings) as if it was part of a configfile,
|
186
|
+
# and *adds* the value accordingly, if it is not already there.
|
187
|
+
def parse(string)
|
188
|
+
if string.class == Array then
|
189
|
+
string
|
190
|
+
else
|
191
|
+
string.split("\n")
|
192
|
+
end.each do |line|
|
193
|
+
if line =~ /^(\w)+ +.+/
|
194
|
+
line = line.strip.split(" ", 2)
|
195
|
+
raise "No option '#{line[0]}' existing!" if @hash[line[0]].nil?
|
196
|
+
@hash[line[0]].add(line[1])
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def preference_text(string)
|
202
|
+
i = (80 - string.length)/2
|
203
|
+
"-"*i + string + "-"*(80-i-string.length)
|
204
|
+
end
|
205
|
+
|
206
|
+
def parse_section(section)
|
207
|
+
if section[0,1] == "=" then
|
208
|
+
@order << [section[1..-2]]
|
209
|
+
return
|
210
|
+
end
|
211
|
+
lines = section.split("\n")
|
212
|
+
first = lines.shift.split(": ")
|
213
|
+
name = first.shift
|
214
|
+
raise InternalError, "Order still empty!" if @order.empty?
|
215
|
+
@order.last << name
|
216
|
+
|
217
|
+
classname = /^[^(]*/.match(first[0]).to_s
|
218
|
+
arguments = /\(.*\)/.match(first[0]).to_s
|
219
|
+
arguments = arguments[1..-2] unless arguments.nil?
|
220
|
+
|
221
|
+
desc = []
|
222
|
+
defaults = []
|
223
|
+
lines.each do |line|
|
224
|
+
if line =~ /^#{name} */ then
|
225
|
+
defaults << line[(name.length+1)..-1] unless line[(name.length+1)..-1].nil?
|
226
|
+
else
|
227
|
+
desc << line
|
228
|
+
end
|
229
|
+
end
|
230
|
+
@hash[name] = eval("Config#{classname}").new(name, arguments.to_s, desc.join("\n"), defaults)
|
231
|
+
end
|
232
|
+
|
233
|
+
private
|
234
|
+
|
235
|
+
def method_missing(name_orig, *args)
|
236
|
+
name = name_orig.to_s
|
237
|
+
if @hash.has_key?(name)
|
238
|
+
@hash[name].value
|
239
|
+
elsif @hash.has_key?(name[0..-2]) and name[-1] == "="[0]
|
240
|
+
@hash[name[0..-2]].set(args.first)
|
241
|
+
else
|
242
|
+
super
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
class ConfigFile
|
248
|
+
|
249
|
+
attr_reader :new
|
250
|
+
|
251
|
+
# Path should be a String. Creates or opens a new configfile and immediately
|
252
|
+
# writes it back again, to add new features etc (just in case).
|
253
|
+
def initialize(path)
|
254
|
+
@path = path
|
255
|
+
@template = ConfigTemplate.new
|
256
|
+
@template.read_template(SMARBS::DATADIR + "/configuration.txt")
|
257
|
+
|
258
|
+
if File.file?(@path)
|
259
|
+
raise @path + " is not writable!" if not File.writable?(@path)
|
260
|
+
read
|
261
|
+
write
|
262
|
+
else
|
263
|
+
if Directory.writable?(File.dirname(@path)) # Create example file
|
264
|
+
FileUtils.makedirs(File.dirname(@path)) # Create directory
|
265
|
+
write
|
266
|
+
puts "First run:\nConfig file created, edit " + @path + "!"
|
267
|
+
@new = true
|
268
|
+
else
|
269
|
+
raise(File.dirname(@path) + " is not writable!")
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Returns the filename (name only!) of the configfile.
|
275
|
+
def filename
|
276
|
+
return File.basename(@path)
|
277
|
+
end
|
278
|
+
|
279
|
+
# Puts the Configfile-text into the given file, with all the options as-is.
|
280
|
+
def write
|
281
|
+
file=File.open(@path, "w")
|
282
|
+
file.puts intro
|
283
|
+
file.puts @template
|
284
|
+
file.puts outro
|
285
|
+
file.close
|
286
|
+
end
|
287
|
+
|
288
|
+
def intro
|
289
|
+
txt = nil
|
290
|
+
File.open(SMARBS::DATADIR + "/intro.txt", "r") do |file|
|
291
|
+
txt = file.readlines
|
292
|
+
end
|
293
|
+
txt[0] = txt[0].strip + " #{SMARBS::VERSION} (#{SMARBS::DATE})\n"
|
294
|
+
txt.join
|
295
|
+
end
|
296
|
+
|
297
|
+
def outro
|
298
|
+
txt = nil
|
299
|
+
File.open(SMARBS::DATADIR + "/outro.txt", "r") do |file|
|
300
|
+
txt = file.readlines
|
301
|
+
end
|
302
|
+
txt.join
|
303
|
+
end
|
304
|
+
|
305
|
+
def read
|
306
|
+
File.open(@path, "r") do |file|
|
307
|
+
lines = file.readlines
|
308
|
+
index1 = lines.index{|string| string.include? "-preferences-"}
|
309
|
+
index2 = lines.index{|string| string.include? "-end of preferences-"}
|
310
|
+
|
311
|
+
raise "Configfile #{@path} is invalid. Please delete it!" if index1 == nil or index2 == nil
|
312
|
+
@template.clear
|
313
|
+
@template.parse(lines[index1..index2])
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
private
|
318
|
+
|
319
|
+
def method_missing(name, *args)
|
320
|
+
eval "@template.#{name}(args[0])"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Specifies a directory that contains smarbs backups.
|
325
|
+
class SmarbsBackupDir < Directory
|
326
|
+
# Creates or reads out a SmarbsBackupDir, testing if it has valid contents.
|
327
|
+
def initialize(directory, ignore_leftovers=false)
|
328
|
+
super(directory, :writable)
|
329
|
+
|
330
|
+
return if files.size == 0 # Return if the directory is empty.
|
331
|
+
list = dirlist
|
332
|
+
numbers = list.collect {|x| x[0]}
|
333
|
+
raise "Two directories with same 'number' detected in " + @dir + "!" if numbers.uniq != numbers
|
334
|
+
raise "Directory with negative 'number' detected in #{@dir}!" if numbers[0] < 0
|
335
|
+
if (not ignore_leftovers) && directory_left
|
336
|
+
raise(NoConfigException, "\nAborted backup directory '#{directory_left}' left in #{@dir}\nMove or delete it to continue!")
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
public
|
341
|
+
|
342
|
+
# Returns the name of the directory (like 12-34-56-backup.0) when a
|
343
|
+
# '...backup.0' directory is left. Otherwise returns false.
|
344
|
+
def directory_left
|
345
|
+
list = dirlist
|
346
|
+
if list[0][0] == 0
|
347
|
+
return (list[0][1]).to_s+"-backup.0"
|
348
|
+
else
|
349
|
+
return false
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns a sorted array of arrays of the splitted directories within the smarbsbackupdir
|
354
|
+
# of the form [7, 12-34-56] (from "12-34-56-backup.7").
|
355
|
+
#
|
356
|
+
# Raises an error, if some directories are "malformed", respectively not in the form <date>-backup.<positive_number>.
|
357
|
+
def dirlist
|
358
|
+
list=files
|
359
|
+
for i in 0...list.size
|
360
|
+
raise "File '#{list[i]}' left in the destination directory #{@dir}!" if not File.directory?(@dir+"/"+list[i]) # No files are allowed.
|
361
|
+
|
362
|
+
tmp = list[i].split("-backup.")
|
363
|
+
raise @dir + list[i] + " has wrong format!" if tmp.size != 2
|
364
|
+
raise @dir + list[i] + " has wrong format in number!" if tmp[1].to_i.to_s != tmp[1]
|
365
|
+
|
366
|
+
list[i]=[tmp[1].to_i, tmp[0]] # Converts "12-34-56-backup.7" to an Array entry [7, 12-34-56].
|
367
|
+
end
|
368
|
+
list.sort!
|
369
|
+
list.compact!
|
370
|
+
return list
|
371
|
+
end
|
372
|
+
|
373
|
+
# Deletes the directory differing most from the "1, 2, 4, 8, 16, ..." scheme.
|
374
|
+
# If no such is found, deletes the last of all the directories. Also logs what
|
375
|
+
# is happening.
|
376
|
+
#
|
377
|
+
# Raises an error if the next deletion would go below the 'minbackuplevels'.
|
378
|
+
def delete(logger, minbackuplevels, oldestfirst = false)
|
379
|
+
list=dirlist
|
380
|
+
deleted=false
|
381
|
+
|
382
|
+
unless list.size > minbackuplevels or minbackuplevels <= 1
|
383
|
+
raise "Not enough space available, next deletion would go below your minbackuplevels of #{minbackuplevels}!"
|
384
|
+
end
|
385
|
+
|
386
|
+
unless list.size > 1
|
387
|
+
raise "Not enough space available to do an incremental backup!"
|
388
|
+
end
|
389
|
+
|
390
|
+
if oldestfirst then
|
391
|
+
a = dirlist[-1][1]
|
392
|
+
b = dirlist[-1][0]
|
393
|
+
else
|
394
|
+
for i in 0...(dirlist.size-1)
|
395
|
+
if (dirlist[i+1][0]-(2**i)).abs < (dirlist[i][0]-(2**i)).abs && dirlist[i][0] != 0 #Smarbs CORE, the secret formula :)
|
396
|
+
deleted=true
|
397
|
+
a = dirlist[i][1]
|
398
|
+
b = dirlist[i][0]
|
399
|
+
break
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
if not deleted
|
404
|
+
a = dirlist[-1][1]
|
405
|
+
b = dirlist[-1][0]
|
406
|
+
end
|
407
|
+
end
|
408
|
+
logger.p("...removing backup." + b.to_s + "...", 1)
|
409
|
+
FileUtils.remove_dir(self.to_s + a + "-backup." + b.to_s)
|
410
|
+
logger.p(@dir.to_s + a + "-backup." + b.to_s + " removed!", 2, true)
|
411
|
+
end
|
412
|
+
|
413
|
+
# Removes all backups directories except the last one
|
414
|
+
# (the one with the smallest 'number').
|
415
|
+
#
|
416
|
+
# Usually, this is "*-backup.0".
|
417
|
+
def remove_except_one
|
418
|
+
list = dirlist
|
419
|
+
for i in 1...list.size do
|
420
|
+
FileUtils.remove_dir "#{@dir}/#{list[i][1]}-backup.#{list[i][0]}"
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
# Increments all the directory numbers by 1. So for example "12-34-56-backup.7" becomes "12-34-56-backup.8".
|
425
|
+
def increment
|
426
|
+
dirlist.reverse.each do |element|
|
427
|
+
original=@dir.to_s+element[1].to_s+"-backup."+element[0].to_s
|
428
|
+
incremented=@dir.to_s+element[1].to_s+"-backup."+(element[0]+1).to_s
|
429
|
+
FileUtils.move(original, incremented)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
class NoConfigException < RuntimeError
|
435
|
+
end
|
436
|
+
|
437
|
+
class InternalError < RuntimeError
|
438
|
+
end
|
data/lib/log.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'syslog'
|
4
|
+
|
5
|
+
# Class to do automated logging to the console, to a logfile and to an email-account.
|
6
|
+
#
|
7
|
+
# It is possible to set the verbosity of logging and various other options.
|
8
|
+
#
|
9
|
+
# $Id$
|
10
|
+
|
11
|
+
class Log
|
12
|
+
# Initializes the logger object. Takes an (optional) path as argument, and
|
13
|
+
# a string ("yes" or "no") or boolean value for the verbosity level within this logfile.
|
14
|
+
#
|
15
|
+
# If the logfile is not yet existing, a new one will be created, if possible. Otherwise an error is thrown.
|
16
|
+
def initialize(logfile="", advancedlog=true, syslog=false)
|
17
|
+
@logfile=logfile.strip
|
18
|
+
@syslog = syslog
|
19
|
+
@mail_initialized = false
|
20
|
+
@smpt=false
|
21
|
+
|
22
|
+
@logging_to_file = false
|
23
|
+
unless @logfile == ""
|
24
|
+
@logfile.insert(0, '/') unless @logfile[0, 1].to_s == "/"
|
25
|
+
@logging_to_file = true
|
26
|
+
end
|
27
|
+
|
28
|
+
@logging_to_file = false if @syslog
|
29
|
+
|
30
|
+
@slog = SyslogWrapper.new() if @syslog
|
31
|
+
|
32
|
+
@advancedlog=advancedlog
|
33
|
+
|
34
|
+
if @logging_to_file and not Directory.writable?(@logfile)
|
35
|
+
@initialized = false
|
36
|
+
raise @logfile.to_s + " is not writable!"
|
37
|
+
elsif @logging_to_file and not File.file?(@logfile)
|
38
|
+
array = @logfile.split("/")
|
39
|
+
array.delete_at(-1)
|
40
|
+
FileUtils.makedirs("/" + array.join("/"))
|
41
|
+
end
|
42
|
+
@initialized = true
|
43
|
+
end
|
44
|
+
|
45
|
+
public
|
46
|
+
# Initialize the email function, and check if all the given parameters are correct.
|
47
|
+
# If tls is true, then see if ruby-openssl is installed.
|
48
|
+
#
|
49
|
+
# If any errors occur, it raises an error.
|
50
|
+
#
|
51
|
+
# Also sends a test email, if testm is set.
|
52
|
+
def initialize_email(email, smtp, port, uname, passwd, tls, testm, backupname)
|
53
|
+
@email=email
|
54
|
+
@smtp=smtp
|
55
|
+
@port=port
|
56
|
+
@uname=uname
|
57
|
+
@passwd=passwd
|
58
|
+
@tls=tls
|
59
|
+
@testm=testm
|
60
|
+
@backupname = backupname
|
61
|
+
|
62
|
+
if (@uname == "" and @passwd != "") or (@passwd == "" and @uname != "")
|
63
|
+
@mail_initialized=false
|
64
|
+
raise "Both or none of the uname and the passwd must be specified!"
|
65
|
+
end
|
66
|
+
|
67
|
+
if @port == ""
|
68
|
+
@mail_initialized = false
|
69
|
+
raise "Port mustn't be empty to send e-mails!"
|
70
|
+
end
|
71
|
+
if @smpt == ""
|
72
|
+
@mail_initialized = false
|
73
|
+
raise "Smtp mustn't be empty to send e-mails!"
|
74
|
+
end
|
75
|
+
|
76
|
+
unless (@email =~ /./ and @email =~ /@/)
|
77
|
+
@mail_initialized = false
|
78
|
+
raise "E-mail provided in Configfile is wrong or empty!"
|
79
|
+
end
|
80
|
+
|
81
|
+
@mail_initialized=true
|
82
|
+
|
83
|
+
if @testm
|
84
|
+
text='From: smarbs <' + @email + '>
|
85
|
+
To: smarbs Admin <'+@email+'>
|
86
|
+
Subject: Test email, ' + @backupname + '
|
87
|
+
This test email was sent to check the smtp-connection of the configfile "' + @backupname + '".
|
88
|
+
The "testm" option in the script should have been automatically disabled by now,
|
89
|
+
so you wont receive test emails anymore.
|
90
|
+
|
91
|
+
---
|
92
|
+
|
93
|
+
For any questions concerning smarbs, you can contact me here: rggjan@gmail.com'
|
94
|
+
sendmail(text)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# if "date" is true, print the date into (only) the logfile. For example:
|
101
|
+
#
|
102
|
+
# 01 Nov 2008 19h23: Backup NOT successful!
|
103
|
+
#
|
104
|
+
# instead of
|
105
|
+
#
|
106
|
+
# Backup NOT successful!
|
107
|
+
|
108
|
+
# levels are:
|
109
|
+
# * 0: debug
|
110
|
+
# * 1: info
|
111
|
+
# * 2: notice
|
112
|
+
# * 3: warning
|
113
|
+
# * 4: error
|
114
|
+
# * 98: print only to command line (special case)
|
115
|
+
# * 99: successmail (special case)
|
116
|
+
|
117
|
+
def p(message, level=1, date=false)
|
118
|
+
case level
|
119
|
+
when 0..1
|
120
|
+
puts message
|
121
|
+
@slog.log(message, level) if @syslog
|
122
|
+
message=Time.now.strftime("%d %b %Y %Hh%M: ")+message if date
|
123
|
+
File.open(@logfile, "a") {|f| f.puts message} if @logging_to_file and @advancedlog
|
124
|
+
|
125
|
+
when 2..3
|
126
|
+
puts message
|
127
|
+
@slog.log(message, level) if @syslog
|
128
|
+
message=Time.now.strftime("%d %b %Y %Hh%M: ")+message if date
|
129
|
+
File.open(@logfile, "a") {|f| f.puts message} if @logging_to_file
|
130
|
+
|
131
|
+
when 4
|
132
|
+
@slog.log(message, level) if @syslog
|
133
|
+
message = Time.now.strftime("\n%d %b %Y %Hh%M: Backup NOT successful!\n") + "The following error occured: " + message
|
134
|
+
puts message
|
135
|
+
File.open(@logfile, "a") {|f| f.puts message } if @logging_to_file
|
136
|
+
|
137
|
+
if @mail_initialized
|
138
|
+
text='From: smarbs <' + @email + '>
|
139
|
+
To: smarbs Admin <'+@email+'>
|
140
|
+
Subject: An error occured in ' + @backupname + '
|
141
|
+
An error occured in ' + @backupname + ":\n" + message
|
142
|
+
|
143
|
+
if @logging_to_file
|
144
|
+
text += '
|
145
|
+
|
146
|
+
Here is the full logfile:
|
147
|
+
|
148
|
+
' + IO.read(@logfile)
|
149
|
+
end
|
150
|
+
text +='
|
151
|
+
|
152
|
+
---
|
153
|
+
|
154
|
+
For any questions concerning smarbs, you can contact me here: rggjan@gmail.com'
|
155
|
+
sendmail(text)
|
156
|
+
end
|
157
|
+
|
158
|
+
when 98
|
159
|
+
puts message
|
160
|
+
when 99
|
161
|
+
if @mail_initialized then
|
162
|
+
text='From: smarbs <' + @email + '>
|
163
|
+
To: smarbs Admin <'+@email+'>
|
164
|
+
Subject: Smarbs, backup "' + @backupname + '" successful
|
165
|
+
Smarbs backup ended with the following message:
|
166
|
+
' + message
|
167
|
+
|
168
|
+
if @logging_to_file then text += '
|
169
|
+
|
170
|
+
Here is the full logfile:
|
171
|
+
|
172
|
+
' + IO.read(@logfile)
|
173
|
+
end
|
174
|
+
text += '
|
175
|
+
|
176
|
+
---
|
177
|
+
|
178
|
+
For any questions concerning smarbs, you can contact me here: rggjan@gmail.com'
|
179
|
+
sendmail(text)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Sends an email with the appropriate message.
|
185
|
+
def sendmail(message)
|
186
|
+
begin
|
187
|
+
smtp = Net::SMTP.new(@smtp, @port)
|
188
|
+
if @uname != ""
|
189
|
+
if @tls then
|
190
|
+
smtp.enable_starttls
|
191
|
+
smtp.start("localhost.localdomain",@uname,@passwd, :plain) do |i|
|
192
|
+
i.send_message message, @email, @email
|
193
|
+
end
|
194
|
+
else
|
195
|
+
smtp.start("localhost.localdomain",@uname,@passwd, :login) do |i|
|
196
|
+
i.send_message message, @email, @email
|
197
|
+
end
|
198
|
+
end
|
199
|
+
else
|
200
|
+
smtp.start do |i|
|
201
|
+
i.send_message message, @email, @email
|
202
|
+
end
|
203
|
+
end
|
204
|
+
rescue Timeout::Error
|
205
|
+
@mail_initialized=false
|
206
|
+
raise "Error, SMTP timed out, " + $!.to_s
|
207
|
+
rescue
|
208
|
+
@mail_initialized=false
|
209
|
+
raise "Error with SMTP authentification, " + $!.to_s
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# $Id$
|